<commit_before>// @flow

const promisify = require('util').promisify;
const kubernetesClient = require('kubernetes-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: jobName,
    projectName,
    openshiftProject,
    branchName,
    sha
  } = JSON.parse(msg.content.toString())

  logger.verbose(`Received BuildDeploykubernetes monitoring task for project: ${projectName}, jobName: ${jobName}, 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 kubernetesConsole = project.kubernetes.consoleUrl.replace(/\/$/, "");
    var kubernetesToken = project.kubernetes.token || ""
  } catch(error) {
    logger.warn(`Error while loading information for project ${projectName}: ${error}`)
    throw(error)
  }

  // kubernetes API object
  const kubernetesApi = new kubernetesClient.Api({
    url: kubernetesConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: kubernetesToken
    },
  });

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

  const kubernetesBatchApi = new OpenShiftClient.Batch({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    }
  });

  let project = {}
  try {
    const namespacesSearch = promisify(kubernetesCore.namespaces.get);
    const namespacesResult = await namespacesSearch({
      qs: {
        fieldSelector: `metadata.name=${openshiftProject}`
      }
    });

    const namespaces = R.propOr([], 'items', namespacesResult);
    if (!R.isEmpty(namespaces)) {
      project = namespaces[0];
    }
  } 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
    }
  }

  let jobInfo;
  try {
    const jobsGet = promisify(
      kubernetesBatchApi.namespaces(openshiftProject).jobs(jobName).get
    );
    jobInfo = await jobsGet();
  } catch (err) {
    if (err.code == 404) {
      logger.error(`Job ${jobName} does not exist, bailing`);
      failTask(taskId);
      return;
    } else {
      logger.error(err);
      throw new Error();
    }
  }

  const buildPhase = project.status.phase.toLowerCase();

  const jobsLogGet = async () => {
    // First fetch the pod(s) used to run this job
    const podsGet = promisify(kubernetesCore.ns(openshiftProject).pods.get);
    const pods = await podsGet({
      qs: {
        labelSelector: `job-name=${jobName}`
      }
    });
    const podNames = pods.items.map(pod => pod.metadata.name);

    // Combine all logs from all pod(s)
    let finalLog = '';
    for (const podName of podNames) {
      const podLogGet = promisify(
        kubernetesCore.ns(openshiftProject).pods(podName).log.get
      );
      const podLog = await podLogGet();

      finalLog =
        finalLog +
        `
========================================
Logs on pod ${podName}
========================================
${podLog}`;
    }

    return finalLog;
  };

  // const buildsLogGet = Promise.promisify(kubernetes.ns(openshiftProject).builds(`${jobName}/log`).get, { context: kubernetes.ns(openshiftProject).builds(`${jobName}/log`) })
  // const routesGet = Promise.promisify(kubernetes.ns(openshiftProject).routes.get, { context: kubernetes.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} ${jobName}. 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-kubernetes:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${jobName}\` not yet started`
      )
      throw new BuildNotCompletedYet(`*[${projectName}]* ${logMessage} Build \`${jobName}\` not yet started`)
      break;

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

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

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

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

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

      let configMap = {};
      try {
        const configMapSearch = promisify(kubernetesCore.namespaces(openshiftProject).configmaps.get);
        const configMapSearchResult = await configMapSearch({
          qs: {
            fieldSelector: `metadata.name=lagoon-env`
          }
        });

        if (!R.isNil(configMapSearchResult)) {
          configMap = configMapSearchResult
        }

        // 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.ROUTE
      const routes = configMap.data.ROUTES.split(',').filter(e => e !== route);
      meta.route = route
      meta.routes = routes
      sendToLagoonLogs('info', projectName, "", `task:builddeploy-kubernetes:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${jobName}\` 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} ${jobName}: 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
        // TODO: This should work but does not

        const deploymentConfigsGet = promisify(kubernetesCore.namespaces(openshiftProject).deployments.get);
        const qs = {
          fieldSelector: `metadata.name=${openshiftProject}`
        };
        const deploymentConfigs = await deployments({});

        // const deploymentConfigsGet = Promise.promisify(
        //   kubernetes.ns(openshiftProject).deploymentconfigs.get, { context: kubernetes.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} ${jobName}: Error while updating environment services in API, Error: ${err}`)
      }
      break;

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

}

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

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

const uploadLogToS3 = async (jobName, 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 {
    jobName,
    projectName,
    openshiftProject,
    branchName,
    sha
  } = JSON.parse(msg.content.toString())

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

  const task = "task:builddeploy-kubernetes:error";
  const msg = `*[${projectName}]* ${logMessage} Build \`${jobName}\` ERROR: \`\`\` ${lastError} \`\`\``;
  sendToLagoonLogs('error', projectName, "", task,  {}, msg);

}

consumeTaskMonitor('builddeploy-kubernetes', messageConsumer, deathHandler);<commit_msg>final info<commit_after>// @flow

const promisify = require('util').promisify;
const kubernetesClient = require('kubernetes-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: jobName,
    projectName,
    openshiftProject,
    branchName,
    sha
  } = JSON.parse(msg.content.toString())

  logger.verbose(`Received BuildDeploykubernetes monitoring task for project: ${projectName}, jobName: ${jobName}, 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 kubernetesConsole = project.kubernetes.consoleUrl.replace(/\/$/, "");
    var kubernetesToken = project.kubernetes.token || ""
  } catch(error) {
    logger.warn(`Error while loading information for project ${projectName}: ${error}`)
    throw(error)
  }

  // kubernetes API object
  const kubernetesApi = new kubernetesClient.Api({
    url: kubernetesConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: kubernetesToken
    },
  });

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

  const kubernetesBatchApi = new kubernetesClient.Batch({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: kubernetesToken
    }
  });

  let project = {}
  try {
    const namespacesSearch = promisify(kubernetesCore.namespaces.get);
    const namespacesResult = await namespacesSearch({
      qs: {
        fieldSelector: `metadata.name=${openshiftProject}`
      }
    });

    const namespaces = R.propOr([], 'items', namespacesResult);
    if (!R.isEmpty(namespaces)) {
      project = namespaces[0];
    }
  } 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
    }
  }

  let jobInfo;
  try {
    const jobsGet = promisify(
      kubernetesBatchApi.namespaces(openshiftProject).jobs(jobName).get
    );
    jobInfo = await jobsGet();
  } catch (err) {
    if (err.code == 404) {
      logger.error(`Job ${jobName} does not exist, bailing`);
      failTask(taskId);
      return;
    } else {
      logger.error(err);
      throw new Error();
    }
  }

  const buildPhase = project.status.phase.toLowerCase();

  const jobsLogGet = async () => {
    // First fetch the pod(s) used to run this job
    const podsGet = promisify(kubernetesCore.ns(openshiftProject).pods.get);
    const pods = await podsGet({
      qs: {
        labelSelector: `job-name=${jobName}`
      }
    });
    const podNames = pods.items.map(pod => pod.metadata.name);

    // Combine all logs from all pod(s)
    let finalLog = '';
    for (const podName of podNames) {
      const podLogGet = promisify(
        kubernetesCore.ns(openshiftProject).pods(podName).log.get
      );
      const podLog = await podLogGet();

      finalLog =
        finalLog +
        `
========================================
Logs on pod ${podName}
========================================
${podLog}`;
    }

    return finalLog;
  };

  // const buildsLogGet = Promise.promisify(kubernetes.ns(openshiftProject).builds(`${jobName}/log`).get, { context: kubernetes.ns(openshiftProject).builds(`${jobName}/log`) })
  // const routesGet = Promise.promisify(kubernetes.ns(openshiftProject).routes.get, { context: kubernetes.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} ${jobName}. 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-kubernetes:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${jobName}\` not yet started`
      )
      throw new BuildNotCompletedYet(`*[${projectName}]* ${logMessage} Build \`${jobName}\` not yet started`)
      break;

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

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

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

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

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

      let configMap = {};
      try {
        const configMapSearch = promisify(kubernetesCore.namespaces(openshiftProject).configmaps.get);
        const configMapSearchResult = await configMapSearch({
          qs: {
            fieldSelector: `metadata.name=lagoon-env`
          }
        });

        if (!R.isNil(configMapSearchResult)) {
          configMap = configMapSearchResult
        }

        // 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.ROUTE
      const routes = configMap.data.ROUTES.split(',').filter(e => e !== route);
      meta.route = route
      meta.routes = routes
      sendToLagoonLogs('info', projectName, "", `task:builddeploy-kubernetes:${buildPhase}`, meta,
        `*[${projectName}]* ${logMessage} Build \`${jobName}\` 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} ${jobName}: 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(
        //   kubernetes.ns(openshiftProject).deploymentconfigs.get, { context: kubernetes.ns(openshiftProject).deploymentconfigs }
        // );
        // const deploymentConfigs = await deploymentConfigsGet();

        // TODO: Using Deployments may be better
        /*

        const deploymentConfigsGet = promisify(kubernetesApi.namespaces(openshiftProject).deployments.get);
        const deploymentConfigs = await deployments({});

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

        */

        const podsGet = promisify(kubernetes.ns(openshiftProject).pods.get);
        const pods = await podsGet()

        const serviceNames = pods.items.reduce(
          (names, pod) => [
            ...names,
            ...pod.spec.containers.reduce(
              (names, container) => [
                ...names,
                container.name
              ],
              []
            )
          ],
          []
        );

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

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

}

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

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

const uploadLogToS3 = async (jobName, 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 {
    jobName,
    projectName,
    openshiftProject,
    branchName,
    sha
  } = JSON.parse(msg.content.toString())

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

  const task = "task:builddeploy-kubernetes:error";
  const msg = `*[${projectName}]* ${logMessage} Build \`${jobName}\` ERROR: \`\`\` ${lastError} \`\`\``;
  sendToLagoonLogs('error', projectName, "", task,  {}, msg);

}

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


<commit_before>var RawnetAdmin = window.RawnetAdmin || {};

RawnetAdmin.menu = function(){

  function toggleNav(link) {
    var   active = $('#mainNav a.active'),
    target = $(link.attr('href')),
    activeMenu = $('#subNav nav.active');

    active.removeClass('active');
    activeMenu.removeClass('active');
    link.addClass('active');
    target.addClass('active');
  }

  function openSearch() {
    var search = $('#searchControl');

    search.fadeIn("fast").addClass('open');
    search.find('input').focus();
    $(document).keyup(function(e) {
      if (e.keyCode === 27) {
        search.fadeOut("fast").removeClass('open');
        $(document).unbind("keyup");
      }else if (e.keyCode === 13) {
        search.find('form').trigger('submit');
      }
    });
  }

  function init() {
    var activeLink = $('#subNav a.active'),
    activeMenu = activeLink.closest('nav'),
    activeSelector = $('#mainNav a[href="#' + activeMenu.attr('id') + '"]');

    activeMenu.addClass('active');
    activeSelector.addClass('active');

    $(document).on('click', '#mainNav a, #dashboardNav a', function(e) {
      e.preventDefault();
      toggleNav($(this));
    });
    $(document).on('click', '#subNav a.search', function(e) {
      e.preventDefault();
      openSearch();
    });
  }

  return {
    init: init
  };

}();
<commit_msg>Allow non-anchor links to click through normally<commit_after>var RawnetAdmin = window.RawnetAdmin || {};

RawnetAdmin.menu = function(){

  function toggleNav(link) {
    var   active = $('#mainNav a.active'),
    target = $(link.attr('href')),
    activeMenu = $('#subNav nav.active');

    active.removeClass('active');
    activeMenu.removeClass('active');
    link.addClass('active');
    target.addClass('active');
  }

  function openSearch() {
    var search = $('#searchControl');

    search.fadeIn("fast").addClass('open');
    search.find('input').focus();
    $(document).keyup(function(e) {
      if (e.keyCode === 27) {
        search.fadeOut("fast").removeClass('open');
        $(document).unbind("keyup");
      }else if (e.keyCode === 13) {
        search.find('form').trigger('submit');
      }
    });
  }

  function init() {
    var activeLink = $('#subNav a.active'),
    activeMenu = activeLink.closest('nav'),
    activeSelector = $('#mainNav a[href="#' + activeMenu.attr('id') + '"]');

    activeMenu.addClass('active');
    activeSelector.addClass('active');

    $(document).on('click', '#mainNav a[href^="#"], #dashboardNav a[href^="#"]', function(e) {
      e.preventDefault();
      toggleNav($(this));
    });
    $(document).on('click', '#subNav a.search', function(e) {
      e.preventDefault();
      openSearch();
    });
  }

  return {
    init: init
  };

}();
<|endoftext|>


<commit_before>/*
	Name: autoComplete
	Author: Raymond Camden & Andy Matthews
	Contributors: Jim Pease (@jmpease)
	Website: http://raymondcamden.com/
			http://andyMatthews.net
	Packed With: http://jsutility.pjoneil.net/
	Version: 1.4.2
*/
(function($) {

	"use strict";

	var defaults = {
		method: 'GET',
		icon: 'arrow-r',
		cancelRequests: false,
		target: $(),
		source: null,
		callback: null,
		link: null,
		minLength: 0,
		transition: 'fade',
		matchFromStart: true,
        termParam : 'term',
        loadingHtml : '
Searching...
',
        interval : 0,
        builder : null
	},
	openXHR = {},
	buildItems = function($this, data, settings) {
		var str;
        if (settings.builder) {
            str = settings.builder.apply($this.eq(0), [data, settings]);
        } else {
            str = [];
            if (data) {
                $.each(data, function(index, value) {
                    // are we working with objects or strings?
                    if ($.isPlainObject(value)) {
                        str.push('
' + value.label + '
');
                    } else {
                        str.push('
' + value + '
');
                    }
                });
            }
        }
        if ($.isArray(str)) str = str.join('');
		$(settings.target).html(str).listview("refresh");

		// is there a callback?
		if (settings.callback !== null && $.isFunction(settings.callback)) {
			attachCallback(settings);
		}

		if (str.length > 0) {
			$this.trigger("targetUpdated.autocomplete");
		} else {
			$this.trigger("targetCleared.autocomplete");
		}
	},
	attachCallback = function(settings) {
		$('li a', $(settings.target)).bind('click.autocomplete',function(e){
			e.stopPropagation();
			e.preventDefault();
			settings.callback(e);
		});
	},
	clearTarget = function($this, $target) {
		$target.html('').listview('refresh').closest("fieldset").removeClass("ui-search-active");
		$this.trigger("targetCleared.autocomplete");
	},
	handleInput = function(e) {
		var $this = $(this),
			id = $this.attr("id"),
			text,
			data,
			settings = $this.jqmData("autocomplete"),
			element_text,
			re;
        if (e) {
            if (e.keyCode == 38) { // up
                $('.ui-btn-active', $(settings.target)).removeClass('ui-btn-active').prevAll('li.ui-btn:eq(0)').addClass('ui-btn-active').length
                    || $('.ui-btn:last', $(settings.target)).addClass('ui-btn-active');
            } else if (e.keyCode == 40) {
                $('.ui-btn-active', $(settings.target)).removeClass('ui-btn-active').nextAll('li.ui-btn:eq(0)').addClass('ui-btn-active').length
                    || $('.ui-btn:first', $(settings.target)).addClass('ui-btn-active');
            } else if (e.keyCode == 13) {
                $('.ui-btn-active a', $(settings.target)).click();
            }
        }
		if (settings) {
			// get the current text of the input field
			text = $this.val();
            // check if it's the same as the last one
            if (settings._lastText === text) return;
            // reset the timeout...
            if (settings._retryTimeout) {
                window.clearTimeout(settings._retryTimeout);
                settings._retryTimeout = null;
            }
            // dont change the result the user is browsing...
            if (e && (e.keyCode == 13 || e.keyCode == 38 || e.keyCode == 40)) return;
			// if we don't have enough text zero out the target
			if (text.length < settings.minLength) {
				clearTarget($this, $(settings.target));
			} else {
                if (settings.interval && Date.now() - settings._lastRequest < settings.interval) {
                    settings._retryTimeout = window.setTimeout($.proxy(handleInput, this), settings.interval - Date.now() + settings._lastRequest );
                    return;
                }
                settings._lastRequest = Date.now();
                // store last text
                settings._lastText = text;

				// are we looking at a source array or remote data?
				if ($.isArray(settings.source)) {
					data = settings.source.sort().filter(function(element) {
						// matching from start, or anywhere in the string?
						if (settings.matchFromStart) {
							// from start
							element_text, re = new RegExp('^' + text, 'i');
						} else {
							// anywhere
							element_text, re = new RegExp(text, 'i');
						}
						if ($.isPlainObject(element)) {
							element_text = element.label;
						} else {
							element_text = element;
						}
						return re.test(element_text);
					});
					buildItems($this, data, settings);
				}
				// Accept a function as source.
				// Function needs to call the callback, which is the first parameter.
				// source:function(text,callback) { mydata = [1,2]; callback(mydata); }
				else if (typeof settings.source === 'function') {

					settings.source(text,function(data){
						buildItems($this, data, settings);
					});

				} else {
                    var ajax = {
						type: settings.method,
                        data: {},
                        dataType: 'json',
						beforeSend: function(jqXHR) {
							if (settings.cancelRequests) {
								if (openXHR[id]) {
									// If we have an open XML HTTP Request for this autoComplete ID, abort it
									openXHR[id].abort();
								} else {
								}
								// Set this request to the open XML HTTP Request list for this ID
								openXHR[id] = jqXHR;
							}
                            if (settings.loadingHtml) {
                                // Set a loading indicator as a temporary stop-gap to the response time issue
                                settings.target.html(settings.loadingHtml).listview('refresh');
                                settings.target.closest("fieldset").addClass("ui-search-active");
                            }
						},
						success: function(data) {
							buildItems($this, data, settings);
						},
						complete: function (jqXHR, textStatus) {
							// Clear this ID's open XML HTTP Request from the list
							if (settings.cancelRequests) {
								openXHR[id] = null;
							}
						}
                    };
                    if ($.isPlainObject(settings.source)) {
                        if (settings.source.callback) {
                            settings.source.callback(text, ajax);
                        }
                        for (var k in settings.source) {
                            if (k != 'callback') ajax[k] = settings.source[k];
                        }
                    } else {
                        ajax.url = settings.source;
                    }
					if (settings.termParam) ajax.data[settings.termParam] = text;
					$.ajax(ajax);
				}
			}
		}
	},
	methods = {
		init: function(options) {
			var el = this;
			el.jqmData("autocomplete", $.extend({}, defaults, options));
			var settings = el.jqmData("autocomplete");
			return el.unbind("keyup.autocomplete")
						.bind("keyup.autocomplete", handleInput)
						.next('.ui-input-clear')
						.bind('click', function(e){
							clearTarget(el, $(settings.target));
						});
		},
		// Allow dynamic update of source and link
		update: function(options) {
			var settings = this.jqmData("autocomplete");
			if (settings) {
				this.jqmData("autocomplete", $.extend(settings, options));
			}
			return this;
		},
		// Method to forcibly clear our target
		clear: function() {
			var settings = this.jqmData("autocomplete");
			if (settings) {
				clearTarget(this, $(settings.target));
			}
			return this;
		},
		// Method to destroy (cleanup) plugin
		destroy: function() {
			var settings = this.jqmData("autocomplete");
			if (settings) {
				clearTarget(this, $(settings.target));
				this.jqmRemoveData("autocomplete");
				this.unbind(".autocomplete");
			}
			return this;
		}
	};

	$.fn.autocomplete = function(method) {
		if (methods[method]) {
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
		} else if (typeof method === 'object' || !method) {
			return methods.init.apply(this, arguments);
		}
	};

})(jQuery);
<commit_msg>enter key opens first link<commit_after>/*
	Name: autoComplete
	Author: Raymond Camden & Andy Matthews
	Contributors: Jim Pease (@jmpease)
	Website: http://raymondcamden.com/
			http://andyMatthews.net
	Packed With: http://jsutility.pjoneil.net/
	Version: 1.4.2
*/
(function($) {

	"use strict";

	var defaults = {
		method: 'GET',
		icon: 'arrow-r',
		cancelRequests: false,
		target: $(),
		source: null,
		callback: null,
		link: null,
		minLength: 0,
		transition: 'fade',
		matchFromStart: true,
        termParam : 'term',
        loadingHtml : '
Searching...
',
        interval : 0,
        builder : null
	},
	openXHR = {},
	buildItems = function($this, data, settings) {
		var str;
        if (settings.builder) {
            str = settings.builder.apply($this.eq(0), [data, settings]);
        } else {
            str = [];
            if (data) {
                $.each(data, function(index, value) {
                    // are we working with objects or strings?
                    if ($.isPlainObject(value)) {
                        str.push('
' + value.label + '
');
                    } else {
                        str.push('
' + value + '
');
                    }
                });
            }
        }
        if ($.isArray(str)) str = str.join('');
		$(settings.target).html(str).listview("refresh");

		// is there a callback?
		if (settings.callback !== null && $.isFunction(settings.callback)) {
			attachCallback(settings);
		}

		if (str.length > 0) {
			$this.trigger("targetUpdated.autocomplete");
		} else {
			$this.trigger("targetCleared.autocomplete");
		}
	},
	attachCallback = function(settings) {
		$('li a', $(settings.target)).bind('click.autocomplete',function(e){
			e.stopPropagation();
			e.preventDefault();
			settings.callback(e);
		});
	},
	clearTarget = function($this, $target) {
		$target.html('').listview('refresh').closest("fieldset").removeClass("ui-search-active");
		$this.trigger("targetCleared.autocomplete");
	},
	handleInput = function(e) {
		var $this = $(this),
			id = $this.attr("id"),
			text,
			data,
			settings = $this.jqmData("autocomplete"),
			element_text,
			re;
        if (e) {
            if (e.keyCode == 38) { // up
                $('.ui-btn-active', $(settings.target)).removeClass('ui-btn-active').prevAll('li.ui-btn:eq(0)').addClass('ui-btn-active').length
                    || $('.ui-btn:last', $(settings.target)).addClass('ui-btn-active');
            } else if (e.keyCode == 40) {
                $('.ui-btn-active', $(settings.target)).removeClass('ui-btn-active').nextAll('li.ui-btn:eq(0)').addClass('ui-btn-active').length
                    || $('.ui-btn:first', $(settings.target)).addClass('ui-btn-active');
            } else if (e.keyCode == 13) {
                $('.ui-btn-active a', $(settings.target)).click().length
                || $('.ui-btn:first a', $(settings.target)).click();
            }
        }
		if (settings) {
			// get the current text of the input field
			text = $this.val();
            // check if it's the same as the last one
            if (settings._lastText === text) return;
            // reset the timeout...
            if (settings._retryTimeout) {
                window.clearTimeout(settings._retryTimeout);
                settings._retryTimeout = null;
            }
            // dont change the result the user is browsing...
            if (e && (e.keyCode == 13 || e.keyCode == 38 || e.keyCode == 40)) return;
			// if we don't have enough text zero out the target
			if (text.length < settings.minLength) {
				clearTarget($this, $(settings.target));
			} else {
                if (settings.interval && Date.now() - settings._lastRequest < settings.interval) {
                    settings._retryTimeout = window.setTimeout($.proxy(handleInput, this), settings.interval - Date.now() + settings._lastRequest );
                    return;
                }
                settings._lastRequest = Date.now();
                // store last text
                settings._lastText = text;

				// are we looking at a source array or remote data?
				if ($.isArray(settings.source)) {
					data = settings.source.sort().filter(function(element) {
						// matching from start, or anywhere in the string?
						if (settings.matchFromStart) {
							// from start
							element_text, re = new RegExp('^' + text, 'i');
						} else {
							// anywhere
							element_text, re = new RegExp(text, 'i');
						}
						if ($.isPlainObject(element)) {
							element_text = element.label;
						} else {
							element_text = element;
						}
						return re.test(element_text);
					});
					buildItems($this, data, settings);
				}
				// Accept a function as source.
				// Function needs to call the callback, which is the first parameter.
				// source:function(text,callback) { mydata = [1,2]; callback(mydata); }
				else if (typeof settings.source === 'function') {

					settings.source(text,function(data){
						buildItems($this, data, settings);
					});

				} else {
                    var ajax = {
						type: settings.method,
                        data: {},
                        dataType: 'json',
						beforeSend: function(jqXHR) {
							if (settings.cancelRequests) {
								if (openXHR[id]) {
									// If we have an open XML HTTP Request for this autoComplete ID, abort it
									openXHR[id].abort();
								} else {
								}
								// Set this request to the open XML HTTP Request list for this ID
								openXHR[id] = jqXHR;
							}
                            if (settings.loadingHtml) {
                                // Set a loading indicator as a temporary stop-gap to the response time issue
                                settings.target.html(settings.loadingHtml).listview('refresh');
                                settings.target.closest("fieldset").addClass("ui-search-active");
                            }
						},
						success: function(data) {
							buildItems($this, data, settings);
						},
						complete: function (jqXHR, textStatus) {
							// Clear this ID's open XML HTTP Request from the list
							if (settings.cancelRequests) {
								openXHR[id] = null;
							}
						}
                    };
                    if ($.isPlainObject(settings.source)) {
                        if (settings.source.callback) {
                            settings.source.callback(text, ajax);
                        }
                        for (var k in settings.source) {
                            if (k != 'callback') ajax[k] = settings.source[k];
                        }
                    } else {
                        ajax.url = settings.source;
                    }
					if (settings.termParam) ajax.data[settings.termParam] = text;
					$.ajax(ajax);
				}
			}
		}
	},
	methods = {
		init: function(options) {
			var el = this;
			el.jqmData("autocomplete", $.extend({}, defaults, options));
			var settings = el.jqmData("autocomplete");
			return el.unbind("keyup.autocomplete")
						.bind("keyup.autocomplete", handleInput)
						.next('.ui-input-clear')
						.bind('click', function(e){
							clearTarget(el, $(settings.target));
						});
		},
		// Allow dynamic update of source and link
		update: function(options) {
			var settings = this.jqmData("autocomplete");
			if (settings) {
				this.jqmData("autocomplete", $.extend(settings, options));
			}
			return this;
		},
		// Method to forcibly clear our target
		clear: function() {
			var settings = this.jqmData("autocomplete");
			if (settings) {
				clearTarget(this, $(settings.target));
			}
			return this;
		},
		// Method to destroy (cleanup) plugin
		destroy: function() {
			var settings = this.jqmData("autocomplete");
			if (settings) {
				clearTarget(this, $(settings.target));
				this.jqmRemoveData("autocomplete");
				this.unbind(".autocomplete");
			}
			return this;
		}
	};

	$.fn.autocomplete = function(method) {
		if (methods[method]) {
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
		} else if (typeof method === 'object' || !method) {
			return methods.init.apply(this, arguments);
		}
	};

})(jQuery);
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import Modal from '../../Modal';
import { Row, Col } from '../../LayoutGrid';
import Button from '../../Button';

const propTypes = {
  heading: PropTypes.string.isRequired,
  message: PropTypes.oneOfType([
    PropTypes.node,
    PropTypes.arrayOf(PropTypes.node),
  ]),
  cancelLabel: PropTypes.string,
  confirmLabel: PropTypes.string,
  buttonStyle: PropTypes.string,
  cancelButtonStyle: PropTypes.string,
  onCancel: PropTypes.func.isRequired,
  onConfirm: PropTypes.func.isRequired,
  open: PropTypes.bool.isRequired,
};

const defaultProps = {
  cancelLabel: 'Cancel',
  confirmLabel: 'Submit',
  buttonStyle: 'primary',
};

const ConfirmationModal = (props) => {
  const testId = props.heading.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
  return (
    <Modal
      open={props.open}
      label={props.heading}
      id={`${testId}-confirmation-modal`}
      scope="module"
      size="small"
      showHeader={false}
    >
      <h1 id={`${testId}-confirmation-modal-heading`}>{props.heading}

      <Row>
        <Col xs>
          <p id={`${testId}-confirmation-modal-message`}>{props.message}

        </Col>
      </Row>
      <Row>
        <Col xs>
          <Button buttonStyle={props.cancelButtonStyle} onClick={props.onCancel} id={`clickable-${testId}-confirmation-cancel`}>{props.cancelLabel}</Button>
          <Button buttonStyle={props.buttonStyle} onClick={props.onConfirm} id={`clickable-${testId}-confirmation-confirm`}>{props.confirmLabel}</Button>
        </Col>
      </Row>
    </Modal>
  );
};

ConfirmationModal.propTypes = propTypes;
ConfirmationModal.defaultProps = defaultProps;

export default ConfirmationModal;
<commit_msg>Cleanup<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import Modal from '../../Modal';
import { Row, Col } from '../../LayoutGrid';
import Button from '../../Button';

const propTypes = {
  heading: PropTypes.string.isRequired,
  message: PropTypes.oneOfType([
    PropTypes.node,
    PropTypes.arrayOf(PropTypes.node),
  ]),
  cancelLabel: PropTypes.string,
  confirmLabel: PropTypes.string,
  buttonStyle: PropTypes.string,
  cancelButtonStyle: PropTypes.string,
  onCancel: PropTypes.func.isRequired,
  onConfirm: PropTypes.func.isRequired,
  open: PropTypes.bool.isRequired,
};

const defaultProps = {
  cancelLabel: 'Cancel',
  confirmLabel: 'Submit',
  buttonStyle: 'primary',
  cancelButtonStyle: 'default',
};

const ConfirmationModal = (props) => {
  const testId = props.heading.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
  return (
    <Modal
      open={props.open}
      label={props.heading}
      id={`${testId}-confirmation-modal`}
      scope="module"
      size="small"
      showHeader={false}
    >
      <h1 id={`${testId}-confirmation-modal-heading`}>{props.heading}

      <Row>
        <Col xs>
          <p id={`${testId}-confirmation-modal-message`}>{props.message}

        </Col>
      </Row>
      <Row>
        <Col xs>
          <Button buttonStyle={props.cancelButtonStyle} onClick={props.onCancel} id={`clickable-${testId}-confirmation-cancel`}>{props.cancelLabel}</Button>
          <Button buttonStyle={props.buttonStyle} onClick={props.onConfirm} id={`clickable-${testId}-confirmation-confirm`}>{props.confirmLabel}</Button>
        </Col>
      </Row>
    </Modal>
  );
};

ConfirmationModal.propTypes = propTypes;
ConfirmationModal.defaultProps = defaultProps;

export default ConfirmationModal;
<|endoftext|>


<commit_before>/*

Content editable jQuery plugin
==============================

by Fetchnotes LLC

Common Public Attribution License Version 1.0.

"The contents of this file are subject to the Common Public Attribution License
Version 1.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.fetchnotes.com/license. The License is based on the Mozilla Public
License Version 1.1 but Sections 14 and 15 have been added to cover use of
software over a computer network and provide for limited attribution for the
Original Developer. In addition, Exhibit A has been modified to be consistent
with Exhibit B.

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
specific language governing rights and limitations under the License.

The Original Code is Fetchnotes.
The Original Developer is the Initial Developer.
The Initial Developer of the Original Code is Fetchnotes LLC. All portions of
the code written by Fetchnotes LLC are Copyright (c) 2012 Fetchnotes LLC. All
Rights Reserved.

*/

jQuery.fn.contentEditable = function(options) {

	// Default options
	if (!options) options = {};
	if (typeof options.fromHTML === 'undefined') {
		options.fromHTML = function(html) {
			return html.replace(/
/g, '\n');
		};
	}
	if (typeof options.toHTML === 'undefined') {
		options.toHTML = function(text) {
			return text.replace(/\n/g, '
') + '
';
		};
	}

	// For every element we've selected...
	return this.each(function() {

		// Get me
		var $this = jQuery(this);

		// Okay, when I'm clicked...
		$this.on('click', function() {

			// Start editing if we aren't already
			if ($this.data('focused')) return;
			$this.data('focused', true);

			// Build a textarea and put it on top of me
			var textarea = document.createElement('textarea');
			var $textarea = jQuery(textarea);
			var offset = $this.offset();
			var top = offset.top + parseFloat($this.css('padding-top'));
			var left = offset.left + parseFloat($this.css('padding-left'));
			$textarea.css({
				'position': 'absolute',
				'top': top,
				'left': left,
				'margin': '0',
				'padding': '0',
				'border-width': '0',
				'font': $this.css('font'),
				'color': 'blue',	// TODO TEMP
				'background-color': 'transparent',
				'outline': 'none',
				'resize': 'none',
				'overflow': 'hidden'
			});
			$textarea.val(options.fromHTML($this.html()));
			$textarea.data('div', this);
			document.body.appendChild(textarea);
			$textarea.focus();

			// When I edit, change the HTML
			$textarea.on('keyup', function() {
				var $this = jQuery(this);
				var $div = jQuery($this.data('div'));
				$div.html(options.toHTML($this.val()));
				$this.width($div.width());
				$this.height($div.height());
			});

			// Make sure the textarea is the right size
			$textarea.width($this.width());
			$textarea.height($this.height());

			// When the textarea is blurred, we're done editing
			$textarea.on('blur', function() {
				var $this = jQuery(this);
				var $div = jQuery($this.data('div'));
				$div.data('focused', false);
				$this.remove();
			});

		});

	});

};
<commit_msg>Fix 1px offset for textarea<commit_after>/*

Content editable jQuery plugin
==============================

by Fetchnotes LLC

Common Public Attribution License Version 1.0.

"The contents of this file are subject to the Common Public Attribution License
Version 1.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.fetchnotes.com/license. The License is based on the Mozilla Public
License Version 1.1 but Sections 14 and 15 have been added to cover use of
software over a computer network and provide for limited attribution for the
Original Developer. In addition, Exhibit A has been modified to be consistent
with Exhibit B.

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
specific language governing rights and limitations under the License.

The Original Code is Fetchnotes.
The Original Developer is the Initial Developer.
The Initial Developer of the Original Code is Fetchnotes LLC. All portions of
the code written by Fetchnotes LLC are Copyright (c) 2012 Fetchnotes LLC. All
Rights Reserved.

*/

jQuery.fn.contentEditable = function(options) {

	// Default options
	if (!options) options = {};
	if (typeof options.fromHTML === 'undefined') {
		options.fromHTML = function(html) {
			return html.replace(/
/g, '\n');
		};
	}
	if (typeof options.toHTML === 'undefined') {
		options.toHTML = function(text) {
			return text.replace(/\n/g, '
') + '
';
		};
	}

	// For every element we've selected...
	return this.each(function() {

		// Get me
		var $this = jQuery(this);

		// Okay, when I'm clicked...
		$this.on('click', function() {

			// Start editing if we aren't already
			if ($this.data('focused')) return;
			$this.data('focused', true);

			// Build a textarea and put it on top of me
			var textarea = document.createElement('textarea');
			var $textarea = jQuery(textarea);
			var offset = $this.offset();
			var top = offset.top + parseFloat($this.css('padding-top')) + 1;
			var left = offset.left + parseFloat($this.css('padding-left')) + 1;
			$textarea.css({
				'position': 'absolute',
				'top': top,
				'left': left,
				'margin': '0',
				'padding': '0',
				'border-width': '0',
				'font': $this.css('font'),
				'color': 'blue',	// TODO TEMP
				'background-color': 'transparent',
				'outline': 'none',
				'resize': 'none',
				'overflow': 'hidden'
			});
			$textarea.val(options.fromHTML($this.html()));
			$textarea.data('div', this);
			document.body.appendChild(textarea);
			$textarea.focus();

			// When I edit, change the HTML
			$textarea.on('keyup', function() {
				var $this = jQuery(this);
				var $div = jQuery($this.data('div'));
				$div.html(options.toHTML($this.val()));
				$this.width($div.width());
				$this.height($div.height());
			});

			// Make sure the textarea is the right size
			$textarea.width($this.width());
			$textarea.height($this.height());

			// When the textarea is blurred, we're done editing
			$textarea.on('blur', function() {
				var $this = jQuery(this);
				var $div = jQuery($this.data('div'));
				$div.data('focused', false);
				$this.remove();
			});

		});

	});

};
<|endoftext|>


<commit_before>//= require can.jquery-all
//= require models/local_storage

(function(can, $){

can.Model.LocalStorage("CMS.Models.DisplayPrefs", {}, {});

can.Control("CMS.Controllers.ResizeWidgets", {
  defaults : {
    containers : []
    , columns_token : "columns"
    , total_columns : 12
  }
}, {

  setup : function(el, opts) {
    this._super && this._super.apply(this, arguments)
    var that = this;
    CMS.Models.DisplayPrefs.findAll().done(function(data) {
      var m = data[0] || new CMS.Models.DisplayPrefs();
      m.save();
      that.options.model = m;
      that.on();
    });
  }

  , init : function(el, newopts) {
    this._super && this._super(newopts);
    this.update(newopts);
  }

  , update : function(newopts) {
    var that = this
    , opts = this.options
    , widths = this.getWidthsForSelector($(this.element))
    , total_width = 0;

    if(!(opts.model[opts.columns_token] instanceof can.Observe))
      opts.model.attr(opts.columns_token, new can.Observe(opts.model[opts.columns_token]));

    for(var i = 0; i < widths.length; i++) {
      total_width += widths[i];
    }
    if(total_width != this.options.total_columns) {
      widths = this.divide_evenly($children.length);
      this.options.model.attr(this.options.columns_token).attr($c.attr("id"), widths);
      this.options.model.save();
    }
    this.update_columns();
    this.on();
  }

  , update_columns : function() {
    var $c = $(this.element)
    , $children = $c.children().not(".width-selector-bar, .width-selector-drag")
    , widths = this.getWidthsForSelector($c);

    for(i = 1; i <= this.options.total_columns; i++) {
      $children.removeClass("span" + i);
    }
    if(!widths || $children.length != widths.length) {
      widths = this.divide_evenly($children.length);
      this.options.model.attr(this.options.columns_token).attr($c.attr("id"), widths);
      this.options.model.save();
    }
    $children.each(function(i, child) {
      $(child).addClass("span" + widths[i]);
    });
  }

  , divide_evenly : function(n) {
    var tc = this.options.total_columns;
    var ret = [];
    while(ret.length < n) {
      ret.push(Math.floor(tc / n));
    }
    if(n % 2) {
      //odd case
      ret[Math.floor(n / 2)] += tc % (ret[0] * ret.length);
    } else {
      //even case
      ret[n / 2 - 1] += Math.floor(tc % (ret[0] * ret.length) / 2);
      ret[n / 2] += Math.ceil(tc % (ret[0] * ret.length) / 2);
    }

    return ret;
  }

  , "{model} change" : function(el, ev, attr, how, newVal, oldVal) {
    var parts = attr.split(".");
    if(parts.length > 1 && parts[0] === this.options.columns_token)
      this.update_columns($("#" + parts[1]));
  }

  , adjust_column : function(container, border_idx, adjustment) {
    var containers = this.options.model[this.options.columns_token];
    var col = this.getWidthsForSelector(container);
    var adjustment = this.normalizeAdjustment(col, border_idx, adjustment);

    if(!adjustment)
      return;

    col.attr(border_idx, col[border_idx] - adjustment);
    col.attr(border_idx - 1, col[border_idx - 1] + adjustment);
    this.options.model.save();
  }

  , normalizeAdjustment : function(col, border_idx, initial_adjustment) {
    var adjustment = initial_adjustment;

    if(border_idx < 1 || border_idx >= col.length)
      return 0;

    //adjustment is +1, border_idx reduced by 1, adjustment should never be a higher number than border_idx width minus 1
    //adjustment is -1, border_idx-1 reduced by 1, adjustment should never be lower than negative( border_idx-1 width minus 1)

    adjustment = Math.min(adjustment, col[border_idx] - 1);
    adjustment = Math.max(adjustment, -col[border_idx - 1] + 1);

    return adjustment;
  }

  , getWidthsForSelector : function(sel) {
    return this.options.model.attr(this.options.columns_token).attr($(sel).attr("id"));
  }

  , getLeftOffset : function(pageX) {
    var $t = $(this.element);
    return Math.round((pageX - $t.offset().left - parseInt($t.css("padding-left"))) / $t.width() * this.options.total_columns);
  }

  , getLeftOffsetAsPixels : function(offset) {
    var $t = $(this.element);
    return offset * $t.width() / this.options.total_columns + $t.offset().left + parseInt($t.css("padding-left")) - $(window).scrollLeft();
  }

  , " mousedown" : "startResize"

  , startResize : function(el, ev) {
    var that = this;
    var origTarget = ev.originalEvent ? ev.originalEvent.target : ev.target;
    var $t = $(this.element);
    if ($t.is(origTarget)) {
      var offset = this.getLeftOffset(ev.pageX);
      var widths = that.getWidthsForSelector($t).slice(0);
      var c_width = that.options.total_columns;
      while(c_width > offset) { //should be >=?
        c_width -= widths.pop();
      }
      //create the bar that shows where the new split will be
      $("

")
      .addClass("width-selector-bar")
      .data("offset", offset)
      .data("start_offset", offset)
      .data("index", widths.length)
      .css({
        width: "5px"
        , height : $t.height()
        , "background-color" : "black"
        , position : "fixed"
        , left : this.getLeftOffsetAsPixels(offset)
        , top : $t.offset().top - $(window).scrollTop()
      }).appendTo($t);
      //create an invisible drag target so we don't drag around a ghost of the bar
      $("

")
      .attr("draggable", true)
      .addClass("width-selector-drag")
      .css({
        left : ev.pageX - $(window).scrollLeft() - 1
        , top : ev.pageY - $(window).scrollTop() - 1
        , position : "fixed"
        , width : "3px"
        , height : "3px"
        , cursor : "e-resize w-resize"
      })
      //.bind("mouseup dragend", this.proxy('completeResize', this.element))
      //.bind("dragover", this.proxy('recalculate', this.element))
      .appendTo($t);
    }
  }

  , completeResize : function(el, ev) {
    var $drag = $(".width-selector-drag");
    if($drag.length) {
      var t = this.element
      , $bar = $(".width-selector-bar")
      , offset = $bar.data("offset")
      , start_offset = $bar.data("start_offset")
      , index = $bar.data("index");

      this.adjust_column(t, index, offset - start_offset);
    }
    $(".width-selector-bar, .width-selector-drag").remove();
  }

  , " mouseup" : "completeResize"
  , " dragend" : "completeResize"

  //, " dragstart" : function(el, ev)  { ev.preventDefault(); }

  , " dragover" : "recalculateDrag"
  , recalculateDrag : function(el, ev) {
    var $drag = $(this.element).find(".width-selector-drag");
    var $bar =  $(this.element).find(".width-selector-bar")
    if($drag.length) {
      var $t = $(this.element)
      , offset = this.getLeftOffset(ev.pageX)
      , adjustment = this.normalizeAdjustment(this.getWidthsForSelector($t), $bar.data("index"), offset - $bar.data("start_offset"));

      offset = $bar.data("start_offset") + adjustment;

      $bar
      .data("offset", offset)
      .css("left", this.getLeftOffsetAsPixels(offset));
      ev.preventDefault();
    }
  }

});

})(this.can, this.can.$);<commit_msg>Story 40306505: Cleanup for newly created model, needed post refactor.<commit_after>//= require can.jquery-all
//= require models/local_storage

(function(can, $){

can.Model.LocalStorage("CMS.Models.DisplayPrefs", {}, {});

can.Control("CMS.Controllers.ResizeWidgets", {
  defaults : {
    containers : []
    , columns_token : "columns"
    , total_columns : 12
  }
}, {

  setup : function(el, opts) {
    this._super && this._super.apply(this, arguments)
    var that = this;
    CMS.Models.DisplayPrefs.findAll().done(function(data) {
      var m = data[0] || new CMS.Models.DisplayPrefs();
      m.save();
      that.options.model = m;
      that.on();
    });
  }

  , init : function(el, newopts) {
    this._super && this._super(newopts);
    this.update(newopts);
  }

  , update : function(newopts) {
    var that = this
    , opts = this.options
    , widths
    , total_width = 0;

    if(!(opts.model[opts.columns_token] instanceof can.Observe))
      opts.model.attr(opts.columns_token, new can.Observe(opts.model[opts.columns_token]));
    widths = this.getWidthsForSelector($(this.element)) || [];

    for(var i = 0; i < widths.length; i++) {
      total_width += widths[i];
    }
    if(total_width != this.options.total_columns) {
      widths = this.divide_evenly($(this.element).children().not(".width-selector-bar, .width-selector-drag").length);
      this.options.model.attr(this.options.columns_token).attr($(this.element).attr("id"), widths);
      this.options.model.save();
    }
    this.update_columns();
    this.on();
  }

  , update_columns : function() {
    var $c = $(this.element)
    , $children = $c.children().not(".width-selector-bar, .width-selector-drag")
    , widths = this.getWidthsForSelector($c);

    for(i = 1; i <= this.options.total_columns; i++) {
      $children.removeClass("span" + i);
    }
    if(!widths || $children.length != widths.length) {
      widths = this.divide_evenly($children.length);
      this.options.model.attr(this.options.columns_token).attr($c.attr("id"), widths);
      this.options.model.save();
    }
    $children.each(function(i, child) {
      $(child).addClass("span" + widths[i]);
    });
  }

  , divide_evenly : function(n) {
    var tc = this.options.total_columns;
    var ret = [];
    while(ret.length < n) {
      ret.push(Math.floor(tc / n));
    }
    if(n % 2) {
      //odd case
      ret[Math.floor(n / 2)] += tc % (ret[0] * ret.length);
    } else {
      //even case
      ret[n / 2 - 1] += Math.floor(tc % (ret[0] * ret.length) / 2);
      ret[n / 2] += Math.ceil(tc % (ret[0] * ret.length) / 2);
    }

    return ret;
  }

  , "{model} change" : function(el, ev, attr, how, newVal, oldVal) {
    var parts = attr.split(".");
    if(parts.length > 1 && parts[0] === this.options.columns_token)
      this.update_columns($("#" + parts[1]));
  }

  , adjust_column : function(container, border_idx, adjustment) {
    var containers = this.options.model[this.options.columns_token];
    var col = this.getWidthsForSelector(container);
    var adjustment = this.normalizeAdjustment(col, border_idx, adjustment);

    if(!adjustment)
      return;

    col.attr(border_idx, col[border_idx] - adjustment);
    col.attr(border_idx - 1, col[border_idx - 1] + adjustment);
    this.options.model.save();
  }

  , normalizeAdjustment : function(col, border_idx, initial_adjustment) {
    var adjustment = initial_adjustment;

    if(border_idx < 1 || border_idx >= col.length)
      return 0;

    //adjustment is +1, border_idx reduced by 1, adjustment should never be a higher number than border_idx width minus 1
    //adjustment is -1, border_idx-1 reduced by 1, adjustment should never be lower than negative( border_idx-1 width minus 1)

    adjustment = Math.min(adjustment, col[border_idx] - 1);
    adjustment = Math.max(adjustment, -col[border_idx - 1] + 1);

    return adjustment;
  }

  , getWidthsForSelector : function(sel) {
    return this.options.model.attr(this.options.columns_token).attr($(sel).attr("id"));
  }

  , getLeftOffset : function(pageX) {
    var $t = $(this.element);
    return Math.round((pageX - $t.offset().left - parseInt($t.css("padding-left"))) / $t.width() * this.options.total_columns);
  }

  , getLeftOffsetAsPixels : function(offset) {
    var $t = $(this.element);
    return offset * $t.width() / this.options.total_columns + $t.offset().left + parseInt($t.css("padding-left")) - $(window).scrollLeft();
  }

  , " mousedown" : "startResize"

  , startResize : function(el, ev) {
    var that = this;
    var origTarget = ev.originalEvent ? ev.originalEvent.target : ev.target;
    var $t = $(this.element);
    if ($t.is(origTarget)) {
      var offset = this.getLeftOffset(ev.pageX);
      var widths = that.getWidthsForSelector($t).slice(0);
      var c_width = that.options.total_columns;
      while(c_width > offset) { //should be >=?
        c_width -= widths.pop();
      }
      //create the bar that shows where the new split will be
      $("

")
      .addClass("width-selector-bar")
      .data("offset", offset)
      .data("start_offset", offset)
      .data("index", widths.length)
      .css({
        width: "5px"
        , height : $t.height()
        , "background-color" : "black"
        , position : "fixed"
        , left : this.getLeftOffsetAsPixels(offset)
        , top : $t.offset().top - $(window).scrollTop()
      }).appendTo($t);
      //create an invisible drag target so we don't drag around a ghost of the bar
      $("

")
      .attr("draggable", true)
      .addClass("width-selector-drag")
      .css({
        left : ev.pageX - $(window).scrollLeft() - 1
        , top : ev.pageY - $(window).scrollTop() - 1
        , position : "fixed"
        , width : "3px"
        , height : "3px"
        , cursor : "e-resize w-resize"
      })
      //.bind("mouseup dragend", this.proxy('completeResize', this.element))
      //.bind("dragover", this.proxy('recalculate', this.element))
      .appendTo($t);
    }
  }

  , completeResize : function(el, ev) {
    var $drag = $(".width-selector-drag");
    if($drag.length) {
      var t = this.element
      , $bar = $(".width-selector-bar")
      , offset = $bar.data("offset")
      , start_offset = $bar.data("start_offset")
      , index = $bar.data("index");

      this.adjust_column(t, index, offset - start_offset);
    }
    $(".width-selector-bar, .width-selector-drag").remove();
  }

  , " mouseup" : "completeResize"
  , " dragend" : "completeResize"

  //, " dragstart" : function(el, ev)  { ev.preventDefault(); }

  , " dragover" : "recalculateDrag"
  , recalculateDrag : function(el, ev) {
    var $drag = $(this.element).find(".width-selector-drag");
    var $bar =  $(this.element).find(".width-selector-bar")
    if($drag.length) {
      var $t = $(this.element)
      , offset = this.getLeftOffset(ev.pageX)
      , adjustment = this.normalizeAdjustment(this.getWidthsForSelector($t), $bar.data("index"), offset - $bar.data("start_offset"));

      offset = $bar.data("start_offset") + adjustment;

      $bar
      .data("offset", offset)
      .css("left", this.getLeftOffsetAsPixels(offset));
      ev.preventDefault();
    }
  }

});

})(this.can, this.can.$);<|endoftext|>


<commit_before>"use strict";
const _ = require("lodash");
const toSafestNumber = require("../../helpers/to-safest-number");
const toSquareMeters = require("../../helpers/to-square-meters");
const toUAH = require("../../helpers/to-uah");

module.exports = {
    getYear: function getYear(declaration) {
        const yearVariant1 = _.get(declaration, "step_0.changesYear");
        const yearVariant2 = _.get(declaration, "step_0.declarationYear1");
        return toSafestNumber(yearVariant1 || yearVariant2);
    },
    getBankAccount: function getBankAccount(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_12"), function (sum, belonging) {
            //belonging.person === "1" &&
            if (_.includes(_.lowerCase(belonging.objectType), "банк")) {
                return sum + toUAH(belonging.sizeAssets, belonging.assetsCurrency);
            }
            return sum;
        }, 0);
    },
    getCash: function getCash() {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_12"), function (sum, belonging) {
            //belonging.person === "1" &&
            if (_.includes(_.lowerCase(belonging.objectType), "готівк")) {
                return sum + toUAH(belonging.sizeAssets, belonging.assetsCurrency);
            }
            return sum;
        }, 0);
    },
    getIncome: function getIncome(declaration) {
        return _.reduce(_.get(declaration, "step_11"), function (sum, belonging) {
            if (belonging.person === "1") {
                return sum + toSafestNumber(belonging.sizeIncome);
            }
            return sum;
        }, 0);
    },
    getCarAmount: function getCarAmount(declaration) {
        return _.reduce(_.get(declaration, "step_6"), function (sum, belonging) {
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "авто")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getFlatArea: function getFlatArea(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "квартира")) {
                return sum + toSquareMeters(belonging.totalArea, "");
            }
            return sum;
        }, 0);
    },
    getFlatAmount: function getFlatAmount(declaration) {
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "квартира")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getHouseArea: function getHouseArea(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "будинок")) {
                return sum + toSquareMeters(belonging.totalArea, "");
            }
            return sum;
        }, 0);
    },
    getHouseAmount: function getHouseAmount(declaration) {
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "будинок")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getLandArea: function getLandArea(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            // "Земельна ділянка"
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "земел")) {
                return sum + toSquareMeters(belonging.totalArea, "");
            }
            return sum;
        }, 0);
    },
    getLandAmount: function getLandAmount(declaration) {
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            // "Земельна ділянка"
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "земел")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getFamilyIncome: function getFamilyIncome(declaration) {
        return _.reduce(_.get(declaration, "step_11"), function (sum, belonging) {
            if (belonging.person !== "1") {
                return sum + toSafestNumber(belonging.sizeIncome);
            }
            return sum;
        }, 0);
    },
    getFamilyCarAmount: function getFamilyCarAmount(declaration) {
        return _.reduce(_.get(declaration, "step_6"), function (sum, belonging) {
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "авто")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getFamilyFlatArea: function familyFlatArea(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "квартира")) {
                return sum + toSquareMeters(belonging.totalArea, "");
            }
            return sum;
        }, 0);
    },
    getFamilyFlatAmount: function familyFlatAmount(declaration) {
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "квартира")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getFamilyHouseArea: function getFamilyHouseArea(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "будинок")) {
                return sum + toSquareMeters(belonging.totalArea, "");
            }
            return sum;
        }, 0);
    },
    getFamilyHouseAmount: function getFamilyHouseAmount(declaration) {
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "будинок")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getFamilyLandArea: function getFamilyLandArea(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            // "Земельна ділянка"
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "земел")) {
                return sum + toSquareMeters(belonging.totalArea, "");
            }
            return sum;
        }, 0);
    },
    getFamilyLandAmount: function getFamilyLandAmount(declaration) {
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            // "Земельна ділянка"
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "земел")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    }
};
<commit_msg>Fix [ReferenceError: declaration is not defined]<commit_after>"use strict";
const _ = require("lodash");
const toSafestNumber = require("../../helpers/to-safest-number");
const toSquareMeters = require("../../helpers/to-square-meters");
const toUAH = require("../../helpers/to-uah");

module.exports = {
    getYear: function getYear(declaration) {
        const yearVariant1 = _.get(declaration, "step_0.changesYear");
        const yearVariant2 = _.get(declaration, "step_0.declarationYear1");
        return toSafestNumber(yearVariant1 || yearVariant2);
    },
    getBankAccount: function getBankAccount(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_12"), function (sum, belonging) {
            //belonging.person === "1" &&
            if (_.includes(_.lowerCase(belonging.objectType), "банк")) {
                return sum + toUAH(belonging.sizeAssets, belonging.assetsCurrency);
            }
            return sum;
        }, 0);
    },
    getCash: function getCash(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_12"), function (sum, belonging) {
            //belonging.person === "1" &&
            if (_.includes(_.lowerCase(belonging.objectType), "готівк")) {
                return sum + toUAH(belonging.sizeAssets, belonging.assetsCurrency);
            }
            return sum;
        }, 0);
    },
    getIncome: function getIncome(declaration) {
        return _.reduce(_.get(declaration, "step_11"), function (sum, belonging) {
            if (belonging.person === "1") {
                return sum + toSafestNumber(belonging.sizeIncome);
            }
            return sum;
        }, 0);
    },
    getCarAmount: function getCarAmount(declaration) {
        return _.reduce(_.get(declaration, "step_6"), function (sum, belonging) {
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "авто")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getFlatArea: function getFlatArea(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "квартира")) {
                return sum + toSquareMeters(belonging.totalArea, "");
            }
            return sum;
        }, 0);
    },
    getFlatAmount: function getFlatAmount(declaration) {
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "квартира")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getHouseArea: function getHouseArea(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "будинок")) {
                return sum + toSquareMeters(belonging.totalArea, "");
            }
            return sum;
        }, 0);
    },
    getHouseAmount: function getHouseAmount(declaration) {
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "будинок")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getLandArea: function getLandArea(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            // "Земельна ділянка"
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "земел")) {
                return sum + toSquareMeters(belonging.totalArea, "");
            }
            return sum;
        }, 0);
    },
    getLandAmount: function getLandAmount(declaration) {
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            // "Земельна ділянка"
            if (belonging.person === "1" && _.includes(_.lowerCase(belonging.objectType), "земел")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getFamilyIncome: function getFamilyIncome(declaration) {
        return _.reduce(_.get(declaration, "step_11"), function (sum, belonging) {
            if (belonging.person !== "1") {
                return sum + toSafestNumber(belonging.sizeIncome);
            }
            return sum;
        }, 0);
    },
    getFamilyCarAmount: function getFamilyCarAmount(declaration) {
        return _.reduce(_.get(declaration, "step_6"), function (sum, belonging) {
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "авто")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getFamilyFlatArea: function familyFlatArea(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "квартира")) {
                return sum + toSquareMeters(belonging.totalArea, "");
            }
            return sum;
        }, 0);
    },
    getFamilyFlatAmount: function familyFlatAmount(declaration) {
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "квартира")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getFamilyHouseArea: function getFamilyHouseArea(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "будинок")) {
                return sum + toSquareMeters(belonging.totalArea, "");
            }
            return sum;
        }, 0);
    },
    getFamilyHouseAmount: function getFamilyHouseAmount(declaration) {
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "будинок")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    },
    getFamilyLandArea: function getFamilyLandArea(declaration) {
        //TODO multiply by belonging.rights.1.percent-ownership
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            // "Земельна ділянка"
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "земел")) {
                return sum + toSquareMeters(belonging.totalArea, "");
            }
            return sum;
        }, 0);
    },
    getFamilyLandAmount: function getFamilyLandAmount(declaration) {
        return _.reduce(_.get(declaration, "step_3"), function (sum, belonging) {
            // "Земельна ділянка"
            if (belonging.person !== "1" && _.includes(_.lowerCase(belonging.objectType), "земел")) {
                return sum + 1;
            }
            return sum;
        }, 0);
    }
};
<|endoftext|>


<commit_before>import Store from 'framework/store';

import AssetsStore from 'shreds/stores/assets';
import ShredsDispatcher from 'shreds/dispatcher';
import { action, event } from 'shreds/constants';

const NavigationStore = new Store({
  oninit() {
    this.regDispatcher(ShredsDispatcher, [
      [action.NAVIGATE,           this.navigate],
      [action.MARK_FEED_AS_READ,  this.markFeedAsRead],
      [action.FAIL_NOTIFY,        this.failHandler],
      [action.RELOAD_NAVIGATION,  this.reloadNavigation],
      [event.FEED_MARKED_AS_READ, this.feedMarkedAsRead],
      [event.ITEM_MARKED_AS_READ, this.itemMarkedAsRead]
    ]);
  },

  getFeed(cid, fid) {
    return this.__data.categories[cid].feeds[fid];
  },

  navigate(payload) {
    let selected = this.__data.selected || (
      this.__data.selected = { cid: null, fid: null }
      );
    if (selected.cid && selected.fid) {
      const selectedFeed = this.getFeed(selected.cid, selected.fid);
      selectedFeed.active = '';
    } else {
      this.__data.categories.forEach(category => {
        category.feeds.forEach(feed => { feed.active = ''; });
      });
    }
    if (payload.cid && payload.fid) {
      const feed = this.getFeed(payload.cid, payload.fid);
      feed.active = ' active';
      selected.cid = payload.cid;
      selected.fid = payload.fid;
    }
    this.emitChange();
  },

  markFeedAsRead(payload) {
    this.__data.__favicons || (this.__data.__favicons = {});
    const
      favicons = this.__data.__favicons,
      feed = this.getFeed(payload.cid, payload.fid),
      key = `${payload.cid}:${payload.fid}`;
    if (!favicons[key]) {
      favicons[key] = feed.favicon;
    }
    feed.favicon = AssetsStore.getData('spinner16x16');
    this.emitChange();
  },

  itemMarkedAsRead(payload) {
    const
      f = payload.data.feed,
      feed = this.getFeed(f.cid, f.id);
    feed.unreadCount = f.unreadCount;
    this.emitChange();
  },

  feedMarkedAsRead(payload) {
    const
      f = payload.data.feed,
      feed = this.getFeed(f.cid, f.id);
    this.restoreFavicon(f.cid, f.id);
    feed.unreadCount = f.unreadCount;
    this.emitChange();
  },

  failHandler(payload) {
    switch (payload.data.type) {
    case action.MARK_FEED_AS_READ:
      this.restoreFavicon(payload.data.cid, payload.data.fid);
      break;
    }
    this.emitChange();
  },

  restoreFavicon(cid, fid) {
    const
      key = `${cid}:${fid}`,
      feed = this.getFeed(cid, fid);
    feed.favicon = this.__data.__favicons[key];
  },

  reloadNavigation(payload) {
    this.refresh(payload.data.data);
    this.emitChange();
  }
});

export default NavigationStore;
<commit_msg>Undefined feeds is undefined<commit_after>import Store from 'framework/store';

import AssetsStore from 'shreds/stores/assets';
import ShredsDispatcher from 'shreds/dispatcher';
import { action, event } from 'shreds/constants';

const NavigationStore = new Store({
  oninit() {
    this.regDispatcher(ShredsDispatcher, [
      [action.NAVIGATE,           this.navigate],
      [action.MARK_FEED_AS_READ,  this.markFeedAsRead],
      [action.FAIL_NOTIFY,        this.failHandler],
      [action.RELOAD_NAVIGATION,  this.reloadNavigation],
      [event.FEED_MARKED_AS_READ, this.feedMarkedAsRead],
      [event.ITEM_MARKED_AS_READ, this.itemMarkedAsRead]
    ]);
  },

  getFeed(cid, fid) {
    return this.__data.categories[cid].feeds[fid];
  },

  navigate(payload) {
    let selected = this.__data.selected || (
      this.__data.selected = { cid: null, fid: null }
      );
    if (selected.cid && selected.fid) {
      const selectedFeed = this.getFeed(selected.cid, selected.fid);
      selectedFeed.active = '';
    } else {
      this.__data.categories.forEach(category => {
        for (var f in category.feeds) { category.feeds[f].active = ''; }
      });
    }
    if (payload.cid && payload.fid) {
      const feed = this.getFeed(payload.cid, payload.fid);
      feed.active = ' active';
      selected.cid = payload.cid;
      selected.fid = payload.fid;
    }
    this.emitChange();
  },

  markFeedAsRead(payload) {
    this.__data.__favicons || (this.__data.__favicons = {});
    const
      favicons = this.__data.__favicons,
      feed = this.getFeed(payload.cid, payload.fid),
      key = `${payload.cid}:${payload.fid}`;
    if (!favicons[key]) {
      favicons[key] = feed.favicon;
    }
    feed.favicon = AssetsStore.getData('spinner16x16');
    this.emitChange();
  },

  itemMarkedAsRead(payload) {
    const
      f = payload.data.feed,
      feed = this.getFeed(f.cid, f.id);
    feed.unreadCount = f.unreadCount;
    this.emitChange();
  },

  feedMarkedAsRead(payload) {
    const
      f = payload.data.feed,
      feed = this.getFeed(f.cid, f.id);
    this.restoreFavicon(f.cid, f.id);
    feed.unreadCount = f.unreadCount;
    this.emitChange();
  },

  failHandler(payload) {
    switch (payload.data.type) {
    case action.MARK_FEED_AS_READ:
      this.restoreFavicon(payload.data.cid, payload.data.fid);
      break;
    }
    this.emitChange();
  },

  restoreFavicon(cid, fid) {
    const
      key = `${cid}:${fid}`,
      feed = this.getFeed(cid, fid);
    feed.favicon = this.__data.__favicons[key];
  },

  reloadNavigation(payload) {
    this.refresh(payload.data.data);
    this.emitChange();
  }
});

export default NavigationStore;
<|endoftext|>


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

    function Enumeration(values) {
        for (var id in values) {
            if (values.hasOwnProperty(id)) {
                this.setValue(id, values[id]);
                this.setValue(convertToPascalCase(values[id].label || values[id]), parseInt(id));
            }
        }

		this.asList = this.toArray();
    }

    Enumeration.prototype.setValue = function (id, value) {
        if (!this[id]) {
            this[id] = value;
        } else {
            throw new Error("Enumeration overwrite attempt ocured for id [" + id + "] and value [" + value + "]!");
        }
    };

    Enumeration.prototype.toArray = function () {
        var result = [];
        for (var id in this) {
            if (this.hasOwnProperty(id) && parseInt(id)) {
                var obj = { id: parseInt(id) };

                if(typeof this[id] === 'string') {
                    obj['label'] = this[id];
                } else {
                    for (var key in this[id]) {
                        if (this[id].hasOwnProperty(key)) {
                            obj[key] = this[id][key];
                        }
                    }
                }

                result.push(obj);
            }
        }

        return result;
    };

    function capitalizeFirstLetter(string) {
        return string.charAt(0).toUpperCase() + string.slice(1);
    }
    function convertToPascalCase(label) {
        return label
            .trim()
            .split(/\s+/g)
            .map(capitalizeFirstLetter)
            .join('');
    }

    window.Enumeration = Enumeration;
}(window));<commit_msg>Whitespace fix<commit_after>(function (window) {
    "use strict";

    function Enumeration(values) {
        for (var id in values) {
            if (values.hasOwnProperty(id)) {
                this.setValue(id, values[id]);
                this.setValue(convertToPascalCase(values[id].label || values[id]), parseInt(id));
            }
        }

        this.asList = this.toArray();
    }

    Enumeration.prototype.setValue = function (id, value) {
        if (!this[id]) {
            this[id] = value;
        } else {
            throw new Error("Enumeration overwrite attempt ocured for id [" + id + "] and value [" + value + "]!");
        }
    };

    Enumeration.prototype.toArray = function () {
        var result = [];
        for (var id in this) {
            if (this.hasOwnProperty(id) && parseInt(id)) {
                var obj = { id: parseInt(id) };

                if(typeof this[id] === 'string') {
                    obj['label'] = this[id];
                } else {
                    for (var key in this[id]) {
                        if (this[id].hasOwnProperty(key)) {
                            obj[key] = this[id][key];
                        }
                    }
                }

                result.push(obj);
            }
        }

        return result;
    };

    function capitalizeFirstLetter(string) {
        return string.charAt(0).toUpperCase() + string.slice(1);
    }
    function convertToPascalCase(label) {
        return label
            .trim()
            .split(/\s+/g)
            .map(capitalizeFirstLetter)
            .join('');
    }

    window.Enumeration = Enumeration;
}(window));<|endoftext|>


<commit_before>var Factlink = window.Factlink = (function() {
  // Empty Factlink object
  var Factlink = {};

  // noConflicts!
  jQuery.noConflict();
  window.$ = function (selector,context) { return new jQuery.fn.init(selector,context || window.parent.document); };
  $.fn = $.prototype = jQuery.fn;
  jQuery.extend($, jQuery);
  Factlink.$ = $;
  Factlink._ = window._.noConflict();
  if ( window.parent.easyXDM ) {
    Factlink.easyXDM = window.parent.easyXDM.noConflict("FACTLINK");
  }

  Factlink._.templateSettings = {
    interpolate : /\{%\=(.+?)%\}/g,
    evaluate : /\{%(.+?)%\}/g
  };

  // Expose the Factlink object to the global object
  return Factlink;
})();

(function(Factlink, $, _, easyXDM, undefined) {
  Factlink.siteUrl = function() {
    return FactlinkConfig.url !== undefined ? FactlinkConfig.url : window.location.href;
  };

  // Create the Factlink container
  Factlink.el = $('<div id="fl" />').appendTo('body');
  // Create template wrapper
  Factlink.tmpl = {};

  // Add the stylesheet
  var $style = $('<link>').attr({
    type: "text/css",
    rel: "stylesheet",
    href: FactlinkConfig.lib + "/dist/css/basic.css?" + (new Date()).getTime()
  }).prependTo('head');
})(window.Factlink, Factlink.$, Factlink._, Factlink.easyXDM);
<commit_msg>the loader.js script now makes the #fl div, so no need for another new element here<commit_after>var Factlink = window.Factlink = (function() {
  // Empty Factlink object
  var Factlink = {};

  // noConflicts!
  jQuery.noConflict();
  window.$ = function (selector,context) { return new jQuery.fn.init(selector,context || window.parent.document); };
  $.fn = $.prototype = jQuery.fn;
  jQuery.extend($, jQuery);
  Factlink.$ = $;
  Factlink._ = window._.noConflict();
  if ( window.parent.easyXDM ) {
    Factlink.easyXDM = window.parent.easyXDM.noConflict("FACTLINK");
  }

  Factlink._.templateSettings = {
    interpolate : /\{%\=(.+?)%\}/g,
    evaluate : /\{%(.+?)%\}/g
  };

  // Expose the Factlink object to the global object
  return Factlink;
})();

(function(Factlink, $, _, easyXDM, undefined) {
  Factlink.siteUrl = function() {
    return FactlinkConfig.url !== undefined ? FactlinkConfig.url : window.location.href;
  };

  // Create the Factlink container
  Factlink.el = $('#fl');
  // Create template wrapper
  Factlink.tmpl = {};

  // Add the stylesheet
  var $style = $('<link>').attr({
    type: "text/css",
    rel: "stylesheet",
    href: FactlinkConfig.lib + "/dist/css/basic.css?" + (new Date()).getTime()
  }).prependTo('head');
})(window.Factlink, Factlink.$, Factlink._, Factlink.easyXDM);
<|endoftext|>