<commit_before>const { KubeConfig } = require('kubernetes-client')
const Client = require('kubernetes-client').Client
const Request = require('kubernetes-client/backends/request')
const parser = require('../../util/parser.js')
const kubeconfig = new KubeConfig()
const consoleLogger = require('../../util/logger.js')
const LRU = require('lru-cache')
const podCache = new LRU({
  max: 2000,
  maxAge: 1000 * 60 * 60
})

var client = null
const FALSE_REGEX = /false/i
const TRUE_REGEX = /true/i
const useLogsEnabledPodAnnotation = TRUE_REGEX.test(
  process.env.USE_LOGS_ENABLED_K8S_ANNOTATIONS || 'true'
)

// The run.sh sets both LOGSENE_ENABLED_DEFAULT and LOGS_ENABLED_DEFAULT to TRUE by default.
// Users should set either of these two to FALSE to disable logging by default for all containers.
// This means you need to use whitelisting to enable logging for certain containers.
// In the ENV for those containers set 'LOGS_ENABLED=true' or 'LOGSENE_ENABLED=true'.
// const LOGS_ENABLED_DEFAULT = TRUE_REGEX.test((process.env.LOGSENE_ENABLED_DEFAULT && process.env.LOGS_ENABLED_DEFAULT) || 'true')

const LOGSENE_ENABLED_DEFAULT = TRUE_REGEX.test(
  process.env.LOGSENE_ENABLED_DEFAULT
)
const LOGS_ENABLED_DEFAULT = TRUE_REGEX.test(process.env.LOGS_ENABLED_DEFAULT)
const FINAL_LOGS_ENABLED_DEFAULT =
  LOGSENE_ENABLED_DEFAULT && LOGS_ENABLED_DEFAULT

if (process.env.KUBERNETES_PORT_443_TCP !== undefined) {
  kubeconfig.loadFromCluster()
} else {
  kubeconfig.loadFromDefault()
}
client = new Client({ backend: new Request({ kubeconfig }) })
client.loadSpec().catch(error => {
  consoleLogger.error('Error in k8s client', error)
})

function kubernetesOutputFilter (
  context,
  config,
  eventEmitter,
  data,
  callback
) {
  // we use the config object to track state of each plugin instance
  if (!config.client) {
    initKubernetesClient(config)
  } else {
    enrichLogs(context, config, eventEmitter, data, callback)
  }
}

function initKubernetesClient (config) {
  // do we run in k8s cluster?
  config.client = client
  config.getPodSpec = function (namespace, podName, cb) {
    this.client.api.v1
      .namespaces(namespace)
      .pods(podName)
      .get(cb)
  }.bind(config)
}

const getPodSpec = async (config, namespace, podName, cb) => {
  try {
    var spec = await config.client.api.v1
      .namespaces(namespace)
      .pods(podName)
      .get()
    cb(null, spec.body)
  } catch (error) {
    cb(new Error('Kubernetes API not ready'))
  }
}

function removeFields (pod, data) {
  if (pod && pod.stRemoveFields === false) {
    return
  }
  var annotations = pod.metadata.annotations
  if (!annotations) {
    pod.stRemoveFields = false
    return
  }
  var removeFields =
    annotations.REMOVE_FIELDS || annotations['sematext.com/logs-remove-fields']
  if (removeFields) {
    var fieldNames = removeFields.split(',')
    for (var i = 0; i < fieldNames.length; i++) {
      delete data[fieldNames[i]]
    }
  } else {
    pod.stRemoveFields = false
  }
}

function checkLogsEnabled (pod, data, context, config) {
  if (pod.stLogEnabled !== undefined) {
    data.stLogEnabled = pod.stLogEnabled

    if (config.debug === true) {
      consoleLogger.log(
        `sematext.com/logs-enabled = ${pod.stLogEnabled} for ${pod.metadata.name}`
      )
    }

    return
  }

  pod.stLogEnabled = FINAL_LOGS_ENABLED_DEFAULT

  if (config.debug === true) {
    consoleLogger.log(
      `sematext.com/logs-enabled = ${pod.stLogEnabled} for ${pod.metadata.name}`
    )
  }

  var annotations = pod.metadata.annotations
  if (annotations) {
    var logsEnabled = annotations['sematext.com/logs-enabled']
    if (logsEnabled !== undefined) {
      if (TRUE_REGEX.test(logsEnabled)) {
        pod.stLogEnabled = true
      } else if (FALSE_REGEX.test(logsEnabled)) {
        pod.stLogEnabled = false
      }
    }
    data.stLogEnabled = pod.stLogEnabled

    if (config.debug === true) {
      consoleLogger.log(
        `sematext.com/logs-enabled = ${pod.stLogEnabled} for ${pod.metadata.name}`
      )
    }
  }
}

function checkLogsReceiverUrl (pod, data, context) {
  var annotations = pod.metadata.annotations
  if (annotations && annotations['sematext.com/logs-receiver-urls']) {
    context.logsReceivers = parser.parseReceiverList(
      annotations['sematext.com/logs-receiver-urls']
    )
    return
  }

  context.logsReceiver =
    annotations && annotations['sematext.com/logs-receiver-url']
}

function addLogsIndex (pod, data) {
  if (pod.stLogsTokenSet === false) {
    return
  }
  if (pod.stLogsTokenSet === true) {
    data._index = pod.stToken
    return
  }
  if (!pod.metadata.annotations) {
    pod.stLogsTokenSet = false
    return
  }
  // get ST Logs Token from pod annotation
  pod.stToken = pod.metadata.annotations['sematext.com/logs-token']
  // get comma separated list of fields from pod annotation
  if (pod.stToken) {
    data._index = pod.stToken
    pod.stLogsTokenSet = true
  } else {
    pod.stLogsTokenSet = false
  }
}

function replaceDockerImageName (pod, data) {
  if (data.kubernetes && data.container && pod.stImageCache) {
    var containerName = data.kubernetes.pod.container.name
    var imageInfo = pod.stImageCache[data.kubernetes.pod.name + containerName]
    if (!imageInfo) {
      return
    }
    if (data.container.image.name === 'sha256') {
      data.container.image.digest = 'sha256:' + data.container.image.tag
    }
    data.container.image.name = imageInfo.name
    data.container.image.tag = imageInfo.tag
  }
}

function processAnnotations (
  data,
  context,
  config,
  pod,
  eventEmitter,
  callback
) {
  if (pod && pod.metadata) {
    if (useLogsEnabledPodAnnotation) {
      checkLogsEnabled(pod, data, context, config)
      // var logsEnabled = context.dockerInspect.LOGSENE_ENABLED
      if (data.stLogEnabled === false) {
        // allow input plugins to close the input stream, e.g. input/docker/docker.js
        eventEmitter.emit('dropLogsRequest', context, data)
        // logs will be droped, skip enrichment
        return callback()
      }
    }
    replaceDockerImageName(pod, data)
    removeFields(pod, data)
    addLogsIndex(pod, data)
    checkLogsReceiverUrl(pod, data, context)
    return callback(null, data)
  }

  // fallback to return data if no pod info found
  return callback(null, data)
}

function getPodCacheKey (data) {
  return `${data.kubernetes.namespace}/${data.kubernetes.pod.name}`
}

function enrichLogs (context, config, eventEmitter, data, callback) {
  if (!(data.kubernetes && data.kubernetes.pod)) {
    return callback(null, data)
  }
  const cachedPod = podCache.get(getPodCacheKey(data))
  if (cachedPod) {
    processAnnotations(data, context, config, cachedPod, eventEmitter, callback)
    if (data.stLogEnabled === false) {
      if (config.debug === true) {
        consoleLogger.log(
          'logs dropped ' +
            data.kubernetes.namespace +
            '/' +
            data.kubernetes.pod.name,
          data.message
        )
      }
    }
  } else {
    getPodSpec(
      config,
      data.kubernetes.namespace,
      data.kubernetes.pod.name,
      function (err, pod) {
        if (err) {
          consoleLogger.log(err.message)
          return callback(null, data)
        }
        podCache.set(getPodCacheKey(data), pod)
        // create hashtable with containerName -> imageInformation
        pod.stImageCache = {}
        if (pod.spec && pod.spec.containers) {
          var podContainers = pod.spec.containers
          for (var i = 0; i < podContainers.length; i++) {
            var container = podContainers[i]
            // split imageName:version
            var imageInfo = container.image.split(':')
            // split registry/imageName
            var imageRegistryInfo = container.image.split('/')
            var imageKey = pod.metadata.name + container.name
            pod.stImageCache[imageKey] = {
              image: container.image,
              name: imageInfo[0],
              registry: imageRegistryInfo[0]
            }
            if (imageInfo.length > 1) {
              pod.stImageCache[imageKey].tag = imageInfo[1]
            }
            if (imageRegistryInfo.length > 1) {
              pod.stImageCache[imageKey].plainImageName = imageRegistryInfo[1]
            }
          }
        }
        if (config.debug) {
          consoleLogger.log('pod spec: ' + JSON.stringify(pod))
        }
        processAnnotations(data, context, pod, eventEmitter, callback)
      }
    )
  }
}

module.exports = kubernetesOutputFilter
<commit_msg>Added log forwarding in initK8sClient<commit_after>const { KubeConfig } = require('kubernetes-client')
const Client = require('kubernetes-client').Client
const Request = require('kubernetes-client/backends/request')
const parser = require('../../util/parser.js')
const kubeconfig = new KubeConfig()
const consoleLogger = require('../../util/logger.js')
const LRU = require('lru-cache')
const podCache = new LRU({
  max: 2000,
  maxAge: 1000 * 60 * 60
})

var client = null
const FALSE_REGEX = /false/i
const TRUE_REGEX = /true/i
const useLogsEnabledPodAnnotation = TRUE_REGEX.test(
  process.env.USE_LOGS_ENABLED_K8S_ANNOTATIONS || 'true'
)

// The run.sh sets both LOGSENE_ENABLED_DEFAULT and LOGS_ENABLED_DEFAULT to TRUE by default.
// Users should set either of these two to FALSE to disable logging by default for all containers.
// This means you need to use whitelisting to enable logging for certain containers.
// In the ENV for those containers set 'LOGS_ENABLED=true' or 'LOGSENE_ENABLED=true'.
// const LOGS_ENABLED_DEFAULT = TRUE_REGEX.test((process.env.LOGSENE_ENABLED_DEFAULT && process.env.LOGS_ENABLED_DEFAULT) || 'true')

const LOGSENE_ENABLED_DEFAULT = TRUE_REGEX.test(
  process.env.LOGSENE_ENABLED_DEFAULT
)
const LOGS_ENABLED_DEFAULT = TRUE_REGEX.test(process.env.LOGS_ENABLED_DEFAULT)
const FINAL_LOGS_ENABLED_DEFAULT =
  LOGSENE_ENABLED_DEFAULT && LOGS_ENABLED_DEFAULT

if (process.env.KUBERNETES_PORT_443_TCP !== undefined) {
  kubeconfig.loadFromCluster()
} else {
  kubeconfig.loadFromDefault()
}
client = new Client({ backend: new Request({ kubeconfig }) })
client.loadSpec().catch(error => {
  consoleLogger.error('Error in k8s client', error)
})

function kubernetesOutputFilter (
  context,
  config,
  eventEmitter,
  data,
  callback
) {
  // we use the config object to track state of each plugin instance
  if (!config.client) {
    initKubernetesClient(context, config, eventEmitter, data, callback)
  } else {
    enrichLogs(context, config, eventEmitter, data, callback)
  }
}

function initKubernetesClient (context, config, eventEmitter, data, callback) {
  // do we run in k8s cluster?
  config.client = client
  config.getPodSpec = function (namespace, podName, cb) {
    this.client.api.v1
      .namespaces(namespace)
      .pods(podName)
      .get(cb)
  }.bind(config)

  enrichLogs(context, config, eventEmitter, data, callback)
}

const getPodSpec = async (config, namespace, podName, cb) => {
  try {
    var spec = await config.client.api.v1
      .namespaces(namespace)
      .pods(podName)
      .get()
    cb(null, spec.body)
  } catch (error) {
    cb(new Error('Kubernetes API not ready'))
  }
}

function removeFields (pod, data) {
  if (pod && pod.stRemoveFields === false) {
    return
  }
  var annotations = pod.metadata.annotations
  if (!annotations) {
    pod.stRemoveFields = false
    return
  }
  var removeFields =
    annotations.REMOVE_FIELDS || annotations['sematext.com/logs-remove-fields']
  if (removeFields) {
    var fieldNames = removeFields.split(',')
    for (var i = 0; i < fieldNames.length; i++) {
      delete data[fieldNames[i]]
    }
  } else {
    pod.stRemoveFields = false
  }
}

function checkLogsEnabled (pod, data, context, config) {
  if (pod.stLogEnabled !== undefined) {
    data.stLogEnabled = pod.stLogEnabled

    if (config.debug === true) {
      consoleLogger.log(
        `sematext.com/logs-enabled = ${pod.stLogEnabled} for ${pod.metadata.name}`
      )
    }

    return
  }

  pod.stLogEnabled = FINAL_LOGS_ENABLED_DEFAULT

  if (config.debug === true) {
    consoleLogger.log(
      `sematext.com/logs-enabled = ${pod.stLogEnabled} for ${pod.metadata.name}`
    )
  }

  var annotations = pod.metadata.annotations
  if (annotations) {
    var logsEnabled = annotations['sematext.com/logs-enabled']
    if (logsEnabled !== undefined) {
      if (TRUE_REGEX.test(logsEnabled)) {
        pod.stLogEnabled = true
      } else if (FALSE_REGEX.test(logsEnabled)) {
        pod.stLogEnabled = false
      }
    }
    data.stLogEnabled = pod.stLogEnabled

    if (config.debug === true) {
      consoleLogger.log(
        `sematext.com/logs-enabled = ${pod.stLogEnabled} for ${pod.metadata.name}`
      )
    }
  }
}

function checkLogsReceiverUrl (pod, data, context) {
  var annotations = pod.metadata.annotations
  if (annotations && annotations['sematext.com/logs-receiver-urls']) {
    context.logsReceivers = parser.parseReceiverList(
      annotations['sematext.com/logs-receiver-urls']
    )
    return
  }

  context.logsReceiver =
    annotations && annotations['sematext.com/logs-receiver-url']
}

function addLogsIndex (pod, data) {
  if (pod.stLogsTokenSet === false) {
    return
  }
  if (pod.stLogsTokenSet === true) {
    data._index = pod.stToken
    return
  }
  if (!pod.metadata.annotations) {
    pod.stLogsTokenSet = false
    return
  }
  // get ST Logs Token from pod annotation
  pod.stToken = pod.metadata.annotations['sematext.com/logs-token']
  // get comma separated list of fields from pod annotation
  if (pod.stToken) {
    data._index = pod.stToken
    pod.stLogsTokenSet = true
  } else {
    pod.stLogsTokenSet = false
  }
}

function replaceDockerImageName (pod, data) {
  if (data.kubernetes && data.container && pod.stImageCache) {
    var containerName = data.kubernetes.pod.container.name
    var imageInfo = pod.stImageCache[data.kubernetes.pod.name + containerName]
    if (!imageInfo) {
      return
    }
    if (data.container.image.name === 'sha256') {
      data.container.image.digest = 'sha256:' + data.container.image.tag
    }
    data.container.image.name = imageInfo.name
    data.container.image.tag = imageInfo.tag
  }
}

function processAnnotations (
  data,
  context,
  config,
  pod,
  eventEmitter,
  callback
) {
  if (pod && pod.metadata) {
    if (useLogsEnabledPodAnnotation) {
      checkLogsEnabled(pod, data, context, config)
      // var logsEnabled = context.dockerInspect.LOGSENE_ENABLED
      if (data.stLogEnabled === false) {
        // allow input plugins to close the input stream, e.g. input/docker/docker.js
        eventEmitter.emit('dropLogsRequest', context, data)
        // logs will be droped, skip enrichment
        return callback()
      }
    }
    replaceDockerImageName(pod, data)
    removeFields(pod, data)
    addLogsIndex(pod, data)
    checkLogsReceiverUrl(pod, data, context)
    return callback(null, data)
  }

  // fallback to return data if no pod info found
  return callback(null, data)
}

function getPodCacheKey (data) {
  return `${data.kubernetes.namespace}/${data.kubernetes.pod.name}`
}

function enrichLogs (context, config, eventEmitter, data, callback) {
  if (!(data.kubernetes && data.kubernetes.pod)) {
    return callback(null, data)
  }
  const cachedPod = podCache.get(getPodCacheKey(data))
  if (cachedPod) {
    processAnnotations(data, context, config, cachedPod, eventEmitter, callback)
    if (data.stLogEnabled === false) {
      if (config.debug === true) {
        consoleLogger.log(
          'logs dropped ' +
            data.kubernetes.namespace +
            '/' +
            data.kubernetes.pod.name,
          data.message
        )
      }
    }
  } else {
    getPodSpec(
      config,
      data.kubernetes.namespace,
      data.kubernetes.pod.name,
      function (err, pod) {
        if (err) {
          consoleLogger.log(err.message)
          return callback(null, data)
        }
        podCache.set(getPodCacheKey(data), pod)
        // create hashtable with containerName -> imageInformation
        pod.stImageCache = {}
        if (pod.spec && pod.spec.containers) {
          var podContainers = pod.spec.containers
          for (var i = 0; i < podContainers.length; i++) {
            var container = podContainers[i]
            // split imageName:version
            var imageInfo = container.image.split(':')
            // split registry/imageName
            var imageRegistryInfo = container.image.split('/')
            var imageKey = pod.metadata.name + container.name
            pod.stImageCache[imageKey] = {
              image: container.image,
              name: imageInfo[0],
              registry: imageRegistryInfo[0]
            }
            if (imageInfo.length > 1) {
              pod.stImageCache[imageKey].tag = imageInfo[1]
            }
            if (imageRegistryInfo.length > 1) {
              pod.stImageCache[imageKey].plainImageName = imageRegistryInfo[1]
            }
          }
        }
        if (config.debug) {
          consoleLogger.log('pod spec: ' + JSON.stringify(pod))
        }
        processAnnotations(data, context, pod, eventEmitter, callback)
      }
    )
  }
}

module.exports = kubernetesOutputFilter
<|endoftext|>


<commit_before>/**
 * App creation stuff for Kalabox.
 *
 * @name create
 */

'use strict';

// The create sauce
module.exports = function() {

  // Intrinsic modules.
  var path = require('path');

  // Npm modules
  var _ = require('lodash');
  var fs = require('fs-extra');
  var inquirer = require('inquirer');

  // Kbox modules
  var kbox = require('./kbox.js');
  var Promise = require('./promise.js');

  // Instantiate our app singleton
  var apps = {};

  // Debug info logging function.
  var log = require('./core/log.js').make('CREATE');

  /**
   * Adds a type of app that you can create and options, interactive inquires
   * and other fun stuff too that app.
   * @memberof create
   * @static
   * @method
   * @arg {string} appName - What app to attach the data to.
   * @arg {Object} data - A task or option to add to the app.
   * @example
   * // This will create a command called `kbox create drupal`.
   * kbox.create.add('drupal', {
   *   task: {
   *     name: 'Drupal',
   *     module: 'kalabox-app-drupal',
   *     description: 'Creates a Drupal app.'
   *   }
   * });
   *
   * // This will add a command line option called `name` to `kbox create drupal`.
   * // It will also add interactive step asking for the name to be inputted if
   * // it is not passed in to the CLI. The result of this will end up at the
   * // top level of the app's kalabox.json in the appName key.
   * kbox.create.add('drupal', {
   *   option: {
   *     name: 'name',
   *     weight: -99,
   *     task: {
   *       kind: 'string',
   *       description: 'The name of your app.',
   *     },
   *     inquire: {
   *       type: 'input',
   *       message: 'What will this app be called',
   *       validate: function(value) {
   *         // @todo some actual validation here
   *         return true;
   *       },
   *       filter: function(value) {
   *         return _.kebabCase(value);
   *       },
   *       default: 'My Drupal App'
   *     },
   *     conf: {
   *       type: 'global',
   *       key: 'appName'
   *     }
   *   }
   * });
   *
   * // This add's an interactive step to `kbox drupal create` asking the
   * // user to select a drupal version.
   * kbox.create.add('drupal', {
   *   option: {
   *     name: 'drupal-version',
   *     weight: -98,
   *     inquire: {
   *       type: 'list',
   *       message: 'What major version of drupal',
   *       default: '7',
   *       choices: Object.keys(drupalMatrix)
   *     }
   *   }
   * });
   */
  var add = function(name, data) {

    /*
     * Helper to get default options
     */
    var getDefaultOptions = function(name, data) {
      return {
        name: null,
        task: null,
        weight: 0,
        inquire: null,
        conf: {
          type: 'pluginconfig',
          key: data.option.name || null,
          plugin: name
        }
      };
    };

    if (!apps[name]) {
      create(name);
    }
    if (data.task) {
      apps[name].task = data.task;
    }
    if (data.option) {
      var merge = _.merge({}, getDefaultOptions(name, data), data.option);
      apps[name].options.push(merge);
    }
  };

  /*
   * Adds a new app plugin to the mix
   */
  var create = function(appName) {
    var appDefaults = {
      name : null,
      task: {
        name: null,
        description: null
      },
      options: []
    };
    apps[appName] = appDefaults;
    apps[appName].name = appName;
  };

  /*
   * Grabs an app plugin, or returns false
   */
  var get = function(appName) {
    if (appName) {
      var options = _.sortBy(apps[appName].options, 'weight');
      apps[appName].options = options;
      return apps[appName];
    }
    return false;
  };

  /*
   * ALL THE APP PLUGINZZZ
   */
  var getAll = function() {
    return apps;
  };

  /*
   * Download the app skeleton and copy over the files
   * optionally this can just update a preexisting skeleton
   */
  var createAppSkeleton = function(app, dest) {

    // Needs downloads
    var needsDownload = (app.task.pkg.url) ? true : false;

    // Start the chain
    return Promise.try(function() {

      // If this is a remote package then download it and return the directory
      if (needsDownload) {
        // Get the stuff we need for downloading
        var downloadDir = kbox.util.disk.getTempDir();
        var downloadFiles = kbox.util.download.downloadFiles;

        // Download the files
        return downloadFiles([app.task.pkg.url], downloadDir)

        .then(function() {
          // We need to actually scan and look for files because we dont
          // know what crazy commit hash github will append to our dir
          // @todo: it can be a big issue if we end up with multiple
          // directories containing the project name
          var downloadedFiles = fs.readdirSync(downloadDir);
          var appDir = _.find(downloadedFiles, function(file) {
            return _.includes(file, app.task.pkg.folder);
          });
          return path.join(downloadDir, appDir, app.task.pkg.path);
        });
      }

      // Otherwise just pass back the local location
      else {
        return app.task.pkg.path;
      }

    })

    // Copy the app over
    .tap(function(dir) {

      return Promise.fromNode(function(cb) {

        // Make sure we overwrite
        var options = {
          clobber: true
        };

        // Helpful debug
        log.debug('Copying', dir, dest, options);

        // Do the copying
        fs.copy(dir, dest, options, cb);

        // Return the source directory
        return dir;

      });
    })

    // Remove download directory so we are always fresh
    // @todo: if we have more precise download dir finding this should
    // be unneeded
    .then(function(dir) {
      if (needsDownload) {
        return Promise.fromNode(function(cb) {
          // Find parent directory
          var dirParts = dir.split(path.sep);
          var removeDir = _.remove(dirParts, function(part) {
            return part !== app.task.pkg.path;
          });
          // Remove that dir
          fs.remove(removeDir.join(path.sep), cb);
        });
      }
    });
  };

  /*
   * Object of user overrides to a default app object
   */
  var getOverrides = function(options, results) {

    // Start the collector
    var overrides = {};

    // Construct the overrides
    _.forEach(options, function(opt) {

      // Add to top level if this is global
      if (opt.conf.type === 'global') {
        overrides[opt.conf.key] = results[opt.name];
      }

      // Else use the conf properties
      else {

        // Grab our object chain
        var type = opt.conf.type;
        var plugin = opt.conf.plugin;
        var key = opt.conf.key;

        // Add in things that might be undefined
        if (!overrides[type]) {
          overrides[type] = {};
        }
        if (!overrides[type][plugin]) {
          overrides[type][plugin] = {};
        }

        // Set the value
        overrides[type][plugin][key] = results[opt.name];
      }
    });

    // Return the overrides
    return overrides;

  };

  /*
   * Take an app skeleton and write relevant metadata to it
   */
  var configureApp = function(app, results, callback) {

    // Figure out where our app skeleton lives
    var dir = (results.dir) ? results.dir : process.cwd();
    var appPath = path.join(dir, results.name);

    // Get paths to our config files
    var kalaboxFile = path.join(appPath, 'kalabox.yml');
    var pkgFile = path.join(appPath, 'package.json');

    // Load up the config
    var defaultConf = kbox.util.yaml.toJson(kalaboxFile);
    var pkgConf = require(pkgFile);

    // Create a starting point for our config that events can
    // hook into and mod
    var data = {
      config: _.merge(defaultConf, getOverrides(app.options, results)),
      results: results
    };

    // Customize pkg.json with our app name
    pkgConf.name = results.name;

    // Let other things mod conf
    return kbox.core.events.emit('pre-create-configure', data)

    // Update source files with our new stuff
    .then(function() {
      kbox.util.yaml.toYamlFile(data.config, kalaboxFile);
      fs.writeFileSync(pkgFile, JSON.stringify(pkgConf, null, 2));
    })

    // This is probably not very helpful but symmetry and all
    .then(function() {
      return kbox.core.events.emit('post-create-configure', data);
    })

    // Return.
    .nodeify(callback);
  };

  /*
   * Create an app and then install it
   */
  var createApp = function(protoApp, results, callback) {

    // Create some globally vars for use in and-thens
    var dir = (results.dir) ? results.dir : process.cwd();
    var dest = path.join(dir, results.name);

    /*
     * Utility function to double check just in case
     * we are in an app but it has not been registered
     */
    var isAppByFiles = function() {
      var kalaboxYaml = path.join(process.cwd(), 'kalabox.yml');
      var pkgJson = path.join(process.cwd(), 'package.json');
      return fs.existsSync(kalaboxYaml) && fs.existsSync(pkgJson);
    };

    // Check to make sure we aren't already inside another app
    // since chaos can ensue this way
    if (kbox.core.deps.contains('app') || isAppByFiles()) {
      throw new Error('Cannot install apps inside of other apps');
    }

    kbox.core.log.status('Creating.');

    // Report to metrics.
    return Promise.try(function() {
      return kbox.metrics.reportAction(['create', protoApp.name].join(':'));
    })

    // Make sure we are in a clean place before we get dirty
    .then(function() {
      kbox.core.log.status('Cleaning up.');
      return kbox.app.cleanup();
    })

    // Emit pre create event.
    .then(function() {
      kbox.core.log.status('Running pre create tasks.');
      return kbox.core.events.emit('pre-create-app', protoApp);
    })

    // Download the app skeleton and extract it to our destination
    .then(function() {
      kbox.core.log.status('Creating app structure.');
      return createAppSkeleton(protoApp, dest);
    })

    // Merge in our settings to the new app
    .then(function() {
      kbox.core.log.status('Configuring app.');
      return configureApp(protoApp, results);
    })

    // Check engine status to prompt install request
    .then(function() {
      kbox.core.log.status('Starting engine.');
      return kbox.engine.up();
    })

    // Install the new app
    .then(function() {

      // Get app config from new app
      var config = kbox.core.config.getAppConfig(dest);

      // Create a new app object
      return kbox.app.create(results.name, config)

      // Register the new app object so we can
      // correctly detech an app context
      .tap(function(app) {
        return kbox.setAppContext(app);
      })
      // Load up all the apps plugins
      .tap(function(app) {
        return kbox.app.loadPlugins(app);
      })
      // Install and start the SOB
      .tap(function(app) {
        kbox.core.log.status('Starting app.');
        return kbox.app.start(app);
      });
    })

    // Emit post create event.
    .tap(function(app) {
      kbox.core.log.status('Running post create tasks.');
      return kbox.core.events.emit('post-create-app', app);
    })

    // Print message
    .then(function(app) {
      console.log(kbox.art.appStart(app));
    })

    // Return.
    .nodeify(callback);

  };

  /*
   * Parse our options meta data into relevant other meta data
   */
  var parseOptions = function(options, type) {
    return _.without(_.map(options, function(option) {
      if (option[type]) {
        option[type].name = option.name;
        return option[type];
      }
    }), undefined);
  };

  /**
   * Assembles create.add metadata and builds a task to create a certain kind
   * of app.
   * @memberof create
   * @static
   * @method
   * @arg {Object} task - A kbox task object.
   * @arg {string} appName - The name of the kind of app to be created.
   * @example
   * // Task to create kalabox apps
   * kbox.tasks.add(function(task) {
   *  kbox.create.buildTask(task, 'frontpage98');
   * });
   */
  var buildTask = function(task, type) {

    // Make sure we are going to add a task with a real app
    if (!get(type)) {
      // todo: something useful besides silentfail
      // todo: never forget how funny this was/is/will always be
      throw new Error('F!');
    }

    // Get the app plugin metadata
    var app = get(type);

    // Create the basic task data
    task.path = ['create', type];
    task.category = 'global';
    task.description = app.task.description;
    task.options = parseOptions(app.options, 'task');

    // Extract our inquiry
    var inquiry = _.identity(parseOptions(app.options, 'inquire'));

    // Add a generic app options to build elsewhere
    task.options.push({
      name: 'dir',
      kind: 'string',
      description: 'Creates the app in this directory. Defaults to CWD.',
    });

    // The func that this app create task runs
    task.func = function(done) {

      // Grab the CLI options that are available
      var options = this.options;

      // Filter out interactive questions based on passed in options
      var questions = kbox.util.cli.filterQuestions(inquiry, options);

      // Launch the inquiry
      inquirer.prompt(questions, function(answers) {

        // Add the create type to the results object
        // NOTE: the create type can be different than the
        // type found in the config aka config.type = php but
        // answers._type = drupal7
        answers._type = type;

        // Create the app
        return createApp(app, _.merge({}, options, answers))

        // Return.
        .nodeify(done);

      });
    };
  };

  return {
    add: add,
    get: get,
    getAll: getAll,
    buildTask: buildTask,
    createApp: createApp
  };

};
<commit_msg>#1159: Added --from option to use for func testing<commit_after>/**
 * App creation stuff for Kalabox.
 *
 * @name create
 */

'use strict';

// The create sauce
module.exports = function() {

  // Intrinsic modules.
  var path = require('path');

  // Npm modules
  var _ = require('lodash');
  var fs = require('fs-extra');
  var inquirer = require('inquirer');

  // Kbox modules
  var kbox = require('./kbox.js');
  var Promise = require('./promise.js');

  // Instantiate our app singleton
  var apps = {};

  // Debug info logging function.
  var log = require('./core/log.js').make('CREATE');

  /**
   * Adds a type of app that you can create and options, interactive inquires
   * and other fun stuff too that app.
   * @memberof create
   * @static
   * @method
   * @arg {string} appName - What app to attach the data to.
   * @arg {Object} data - A task or option to add to the app.
   * @example
   * // This will create a command called `kbox create drupal`.
   * kbox.create.add('drupal', {
   *   task: {
   *     name: 'Drupal',
   *     module: 'kalabox-app-drupal',
   *     description: 'Creates a Drupal app.'
   *   }
   * });
   *
   * // This will add a command line option called `name` to `kbox create drupal`.
   * // It will also add interactive step asking for the name to be inputted if
   * // it is not passed in to the CLI. The result of this will end up at the
   * // top level of the app's kalabox.json in the appName key.
   * kbox.create.add('drupal', {
   *   option: {
   *     name: 'name',
   *     weight: -99,
   *     task: {
   *       kind: 'string',
   *       description: 'The name of your app.',
   *     },
   *     inquire: {
   *       type: 'input',
   *       message: 'What will this app be called',
   *       validate: function(value) {
   *         // @todo some actual validation here
   *         return true;
   *       },
   *       filter: function(value) {
   *         return _.kebabCase(value);
   *       },
   *       default: 'My Drupal App'
   *     },
   *     conf: {
   *       type: 'global',
   *       key: 'appName'
   *     }
   *   }
   * });
   *
   * // This add's an interactive step to `kbox drupal create` asking the
   * // user to select a drupal version.
   * kbox.create.add('drupal', {
   *   option: {
   *     name: 'drupal-version',
   *     weight: -98,
   *     inquire: {
   *       type: 'list',
   *       message: 'What major version of drupal',
   *       default: '7',
   *       choices: Object.keys(drupalMatrix)
   *     }
   *   }
   * });
   */
  var add = function(name, data) {

    /*
     * Helper to get default options
     */
    var getDefaultOptions = function(name, data) {
      return {
        name: null,
        task: null,
        weight: 0,
        inquire: null,
        conf: {
          type: 'pluginconfig',
          key: data.option.name || null,
          plugin: name
        }
      };
    };

    if (!apps[name]) {
      create(name);
    }
    if (data.task) {
      apps[name].task = data.task;
    }
    if (data.option) {
      var merge = _.merge({}, getDefaultOptions(name, data), data.option);
      apps[name].options.push(merge);
    }
  };

  /*
   * Adds a new app plugin to the mix
   */
  var create = function(appName) {
    var appDefaults = {
      name : null,
      task: {
        name: null,
        description: null
      },
      options: []
    };
    apps[appName] = appDefaults;
    apps[appName].name = appName;
  };

  /*
   * Grabs an app plugin, or returns false
   */
  var get = function(appName) {
    if (appName) {
      var options = _.sortBy(apps[appName].options, 'weight');
      apps[appName].options = options;
      return apps[appName];
    }
    return false;
  };

  /*
   * ALL THE APP PLUGINZZZ
   */
  var getAll = function() {
    return apps;
  };

  /*
   * Download the app skeleton and copy over the files
   * optionally this can just update a preexisting skeleton
   */
  var createAppSkeleton = function(app, dest, from) {

    // Needs downloads
    var needsDownload = (app.task.pkg.url && !from) ? true : false;

    // Start the chain
    return Promise.try(function() {

      // If this is a remote package then download it and return the directory
      if (needsDownload) {
        // Get the stuff we need for downloading
        var downloadDir = kbox.util.disk.getTempDir();
        var downloadFiles = kbox.util.download.downloadFiles;

        // Download the files
        return downloadFiles([app.task.pkg.url], downloadDir)

        .then(function() {
          // We need to actually scan and look for files because we dont
          // know what crazy commit hash github will append to our dir
          // @todo: it can be a big issue if we end up with multiple
          // directories containing the project name
          var downloadedFiles = fs.readdirSync(downloadDir);
          var appDir = _.find(downloadedFiles, function(file) {
            return _.includes(file, app.task.pkg.folder);
          });
          return path.join(downloadDir, appDir, app.task.pkg.path);
        });
      }

      // Otherwise just pass back the local location
      else {
        return from || app.task.pkg.path;
      }

    })

    // Copy the app over
    .tap(function(dir) {

      return Promise.fromNode(function(cb) {

        // Make sure we overwrite
        var options = {
          clobber: true
        };

        // Helpful debug
        log.debug('Copying', dir, dest, options);

        // Do the copying
        fs.copy(dir, dest, options, cb);

        // Return the source directory
        return dir;

      });
    })

    // Remove download directory so we are always fresh
    // @todo: if we have more precise download dir finding this should
    // be unneeded
    .then(function(dir) {
      if (needsDownload) {
        return Promise.fromNode(function(cb) {
          // Find parent directory
          var dirParts = dir.split(path.sep);
          var removeDir = _.remove(dirParts, function(part) {
            return part !== app.task.pkg.path;
          });
          // Remove that dir
          fs.remove(removeDir.join(path.sep), cb);
        });
      }
    });
  };

  /*
   * Object of user overrides to a default app object
   */
  var getOverrides = function(options, results) {

    // Start the collector
    var overrides = {};

    // Construct the overrides
    _.forEach(options, function(opt) {

      // Add to top level if this is global
      if (opt.conf.type === 'global') {
        overrides[opt.conf.key] = results[opt.name];
      }

      // Else use the conf properties
      else {

        // Grab our object chain
        var type = opt.conf.type;
        var plugin = opt.conf.plugin;
        var key = opt.conf.key;

        // Add in things that might be undefined
        if (!overrides[type]) {
          overrides[type] = {};
        }
        if (!overrides[type][plugin]) {
          overrides[type][plugin] = {};
        }

        // Set the value
        overrides[type][plugin][key] = results[opt.name];
      }
    });

    // Return the overrides
    return overrides;

  };

  /*
   * Take an app skeleton and write relevant metadata to it
   */
  var configureApp = function(app, results, callback) {

    // Figure out where our app skeleton lives
    var dir = (results.dir) ? results.dir : process.cwd();
    var appPath = path.join(dir, results.name);

    // Get paths to our config files
    var kalaboxFile = path.join(appPath, 'kalabox.yml');
    var pkgFile = path.join(appPath, 'package.json');

    // Load up the config
    var defaultConf = kbox.util.yaml.toJson(kalaboxFile);
    var pkgConf = require(pkgFile);

    // Create a starting point for our config that events can
    // hook into and mod
    var data = {
      config: _.merge(defaultConf, getOverrides(app.options, results)),
      results: results
    };

    // Customize pkg.json with our app name
    pkgConf.name = results.name;

    // Let other things mod conf
    return kbox.core.events.emit('pre-create-configure', data)

    // Update source files with our new stuff
    .then(function() {
      kbox.util.yaml.toYamlFile(data.config, kalaboxFile);
      fs.writeFileSync(pkgFile, JSON.stringify(pkgConf, null, 2));
    })

    // This is probably not very helpful but symmetry and all
    .then(function() {
      return kbox.core.events.emit('post-create-configure', data);
    })

    // Return.
    .nodeify(callback);
  };

  /*
   * Create an app and then install it
   */
  var createApp = function(protoApp, results, callback) {

    // Create some globally vars for use in and-thens
    var dir = (results.dir) ? results.dir : process.cwd();
    var dest = path.join(dir, results.name);

    /*
     * Utility function to double check just in case
     * we are in an app but it has not been registered
     */
    var isAppByFiles = function() {
      var kalaboxYaml = path.join(process.cwd(), 'kalabox.yml');
      var pkgJson = path.join(process.cwd(), 'package.json');
      return fs.existsSync(kalaboxYaml) && fs.existsSync(pkgJson);
    };

    // Check to make sure we aren't already inside another app
    // since chaos can ensue this way
    if (kbox.core.deps.contains('app') || isAppByFiles()) {
      throw new Error('Cannot install apps inside of other apps');
    }

    kbox.core.log.status('Creating.');

    // Report to metrics.
    return Promise.try(function() {
      return kbox.metrics.reportAction(['create', protoApp.name].join(':'));
    })

    // Make sure we are in a clean place before we get dirty
    .then(function() {
      kbox.core.log.status('Cleaning up.');
      return kbox.app.cleanup();
    })

    // Emit pre create event.
    .then(function() {
      kbox.core.log.status('Running pre create tasks.');
      return kbox.core.events.emit('pre-create-app', protoApp);
    })

    // Download the app skeleton and extract it to our destination
    .then(function() {
      kbox.core.log.status('Creating app structure.');
      return createAppSkeleton(protoApp, dest, results.from);
    })

    // Merge in our settings to the new app
    .then(function() {
      kbox.core.log.status('Configuring app.');
      return configureApp(protoApp, results);
    })

    // Check engine status to prompt install request
    .then(function() {
      kbox.core.log.status('Starting engine.');
      return kbox.engine.up();
    })

    // Install the new app
    .then(function() {

      // Get app config from new app
      var config = kbox.core.config.getAppConfig(dest);

      // Create a new app object
      return kbox.app.create(results.name, config)

      // Register the new app object so we can
      // correctly detech an app context
      .tap(function(app) {
        return kbox.setAppContext(app);
      })
      // Load up all the apps plugins
      .tap(function(app) {
        return kbox.app.loadPlugins(app);
      })
      // Install and start the SOB
      .tap(function(app) {
        kbox.core.log.status('Starting app.');
        return kbox.app.start(app);
      });
    })

    // Emit post create event.
    .tap(function(app) {
      kbox.core.log.status('Running post create tasks.');
      return kbox.core.events.emit('post-create-app', app);
    })

    // Print message
    .then(function(app) {
      console.log(kbox.art.appStart(app));
    })

    // Return.
    .nodeify(callback);

  };

  /*
   * Parse our options meta data into relevant other meta data
   */
  var parseOptions = function(options, type) {
    return _.without(_.map(options, function(option) {
      if (option[type]) {
        option[type].name = option.name;
        return option[type];
      }
    }), undefined);
  };

  /**
   * Assembles create.add metadata and builds a task to create a certain kind
   * of app.
   * @memberof create
   * @static
   * @method
   * @arg {Object} task - A kbox task object.
   * @arg {string} appName - The name of the kind of app to be created.
   * @example
   * // Task to create kalabox apps
   * kbox.tasks.add(function(task) {
   *  kbox.create.buildTask(task, 'frontpage98');
   * });
   */
  var buildTask = function(task, type) {

    // Make sure we are going to add a task with a real app
    if (!get(type)) {
      // todo: something useful besides silentfail
      // todo: never forget how funny this was/is/will always be
      throw new Error('F!');
    }

    // Get the app plugin metadata
    var app = get(type);

    // Create the basic task data
    task.path = ['create', type];
    task.category = 'global';
    task.description = app.task.description;
    task.options = parseOptions(app.options, 'task');

    // Extract our inquiry
    var inquiry = _.identity(parseOptions(app.options, 'inquire'));

    // Add a generic app options to build elsewhere
    task.options.push({
      name: 'dir',
      kind: 'string',
      description: 'Creates the app in this directory. Defaults to CWD.',
    });

    // Specify an alternate location to grab the app skeleton
    task.options.push({
      name: 'from',
      kind: 'string',
      description: 'Local path to override app skeleton (be careful with this)',
    });

    // The func that this app create task runs
    task.func = function(done) {

      // Grab the CLI options that are available
      var options = this.options;

      // Filter out interactive questions based on passed in options
      var questions = kbox.util.cli.filterQuestions(inquiry, options);

      // Launch the inquiry
      inquirer.prompt(questions, function(answers) {

        // Add the create type to the results object
        // NOTE: the create type can be different than the
        // type found in the config aka config.type = php but
        // answers._type = drupal7
        answers._type = type;

        // Create the app
        return createApp(app, _.merge({}, options, answers))

        // Return.
        .nodeify(done);

      });
    };
  };

  return {
    add: add,
    get: get,
    getAll: getAll,
    buildTask: buildTask,
    createApp: createApp
  };

};
<|endoftext|>


<commit_before>"use strict";

;(function ( root, name, definition ) {
    /*
     * Exports
     */
    if ( typeof define === 'function' && define.amd ) {
        define( [], definition );
    }
    else if ( typeof module === 'object' && module.exports ) {
        module.exports = definition();
    }
    else {
        root[ name ] = definition();
    }
})( this, 'crouch', function () {
    /**
     * RegExp to find placeholders in the template
     *
     * http://regexr.com/3e1o7
     * @type {RegExp}
     */
    var _re = /{([0-9a-zA-Z]+?)}/g;

    /**
     * Micro template compiler
     *
     * @param {string} template
     * @param {array|object} values
     * @returns {string}
     */
    var crouch = function ( template, values ) {
        /*
         * Default arguments
         */
        var
            template = template || "",
            values   = values || {};

        var match;

        /*
         * Loop through all the placeholders that matched with regex
         */
        while ( match = _re.exec( template ) ) {
            /*
             * Get value from given values and
             * if it doesn't exist use empty string
             */
            var _value = values[ match[ 1 ] ];
            if ( !_value ) _value = "";

            /*
             * Replace the placeholder with a real value.
             */
            template = template.replace( match[ 0 ], _value )
        }

        /*
         * Return the template with filled in values
         */
        return template;
    };

    /**
     * 😎
     */
    return crouch;
} );
<commit_msg>Update regex to match underscore and be case insensitive;<commit_after>"use strict";

;(function ( root, name, definition ) {
    /*
     * Exports
     */
    if ( typeof define === 'function' && define.amd ) {
        define( [], definition );
    }
    else if ( typeof module === 'object' && module.exports ) {
        module.exports = definition();
    }
    else {
        root[ name ] = definition();
    }
})( this, 'crouch', function () {
    /**
     * RegExp to find placeholders in the template
     *
     * http://regexr.com/3eveu
     * @type {RegExp}
     */
    var _re = /{([0-9a-z_]+?)}/ig;

    /**
     * Micro template compiler
     *
     * @param {string} template
     * @param {array|object} values
     * @returns {string}
     */
    var crouch = function ( template, values ) {
        /*
         * Default arguments
         */
        var
            template = template || "",
            values   = values || {};

        var match;

        /*
         * Loop through all the placeholders that matched with regex
         */
        while ( match = _re.exec( template ) ) {
            /*
             * Get value from given values and
             * if it doesn't exist use empty string
             */
            var _value = values[ match[ 1 ] ];
            if ( !_value ) _value = "";

            /*
             * Replace the placeholder with a real value.
             */
            template = template.replace( match[ 0 ], _value )
        }

        /*
         * Return the template with filled in values
         */
        return template;
    };

    /**
     * 😎
     */
    return crouch;
} );
<|endoftext|>


<commit_before>/**
 Protein Engineering Analysis Tool Structure Analysis (PEATSA)
 Copyright (C) 2010 Michael Johnston & Jens Erik Nielsen

 Author: Michael Johnston

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

 Contact information:
 Email: Jens.Nielsen_at_gmail.com
 Normal mail:
 Jens Nielsen
 SBBS, Conway Institute
 University College Dublin
 Dublin 4, Ireland
 **/

//Functions for coloring the pdb structure displayed in Jmol on the results page
//It requires that JSGetCalculationData.php is included.

//Returns an array containing the data for calculation.
//If calculation is not finished this function returns nil
function dataForCalculation(calculation)
{
	if(calculation == "Stability")
	{
		return create_Stability_data_array();
	}
	else if(calculation == "Scan")
	{
		return create_Scan_data_array();
	}
	else if(calculation == "Binding")
	{
		return create_Binding_data_array();
	}
	else if(calculation == "Modelling")
	{
		return create_Modelling_data_array();
	}
}

Array.prototype.max = function()
{
	var max = this[0];
	var len = this.length;
	for (var i = 1; i < len; i++)
	{
		if (this[i] > max)
		{
			max = this[i];
		}
	}
	return max;
}

Array.prototype.min = function()
{
	var min = this[0];
	var len = this.length;
	for (var i = 1; i < len; i++)
	{
		if (this[i] < min)
		{
			min = this[i];
		}
	}
	return min;
}

function jmol_array_from_array(data)
{
	var result = "{";
	for(var i=0; i<data.length; i++)
	{
		if(i==0)
		{
			result = result + data[i][1];
			//window.console.log(data[i]);
		}
		else
		{
			result = result + "," + data[i][1];
		}
	}

	result = result + "}";

	return result;
}

//Parse a reduced mutation code ($Chain$ResidueIndex$ResidueCode$MutationCode)
//into a four element array.
function parseMutationCode(code)
{
	//Some pdbs may not have a chain id, so we have to check if one is present
	chain = code.substring(0,1);
	if((parseInt(chain) == 0) || isNaN(parseInt(chain)))
	{
		residueNumber = code.substring(1, code.length - 2);
		residueCode = code.substring(code.length -2, code.length - 1);
		mutationCode = code.substring(code.length -1, code.length);
	}
	else
	{
		chain = "";
		residueNumber = code.substring(0, code.length - 2);
		residueCode = code.substring(code.length -2, code.length - 1);
		mutationCode = code.substring(code.length -1, code.length);
	}

	return new Array(chain, residueNumber, residueCode,  mutationCode);
}

//Function connected to the color structure radio button array
//value is a string indicating how to colour the structure
//the valid values are structure, Scan, Binding, Stability.
//Also sets the min and max scale values.
function colorStructure(value)
{
	if(value == "structure")
	{
		jmolScript('select {*}');
		jmolScript('color ribbon structure;');
		HideContent('Scale');
	}
	else
	{
		var values = new Array();

		//jmolScript('{*}.temperature=0.01');
		jmolScript('color ribbon None');

		list = '(';
		var data = dataForCalculation(value);
		for(var i=0; i<data.length; i++)
		{
			values[i] = parseFloat(data[i][1]);
			//Amazingly you can't set temperature to 0 in Jmol
			//Have to use some small non-zero number
			if(values[i] == 0.0)
			{
				data[i][1] = '0.0000001';
			}
			var script = '.CA}.temperature=';
			var codeData = parseMutationCode(data[i][0]);
			selectionString =  codeData[1];
			if(codeData[0] != "")
	   		{
				selectionString = selectionString + ':' + codeData[0];
	   		}
			script = '{'+ selectionString + script + data[i][1];
			jmolScript(script);
			list = list + selectionString + '.CA';
			if(i != data.length - 1)
				list = list + ',';
		}
		list = list + ')';
		command = 'select ' + list + ';set rangeSelected on; color ribbon relativeTemperature';
		jmolScript(command);

		//Set the scale values
		var min = values.min();
		var max = values.max();
		var mid = (max + min)*0.5;
		//Round to three decimal places
		mid = Math.round(mid*Math.pow(10,3))/Math.pow(10,3);
		document.getElementById('maxvalue').innerHTML = max;
		document.getElementById('minvalue').innerHTML = min;
		document.getElementById('midvalue').innerHTML = mid;
		ShowContent('Scale');
	}
}

//Taken from http://www.codeproject.com/KB/miscctrl/JS_Inspect_Object.aspx
function inspect(obj, maxLevels, level)
{
	var str = '', type, msg;

	// Start Input Validations
	// Don't touch, we start iterating at level zero
	if(level == null)  level = 0;

	// At least you want to show the first level
	if(maxLevels == null) maxLevels = 1;
	if(maxLevels < 1)
		return 'Error: Levels number must be > 0';

	// We start with a non null object
	if(obj == null)
		return 'Error: Object NULL';
	// End Input Validations

	// Each Iteration must be indented
	str += '
';

	// Start iterations for all objects in obj
	for(property in obj)
	{
		try
		{
			// Show "property" and "type property"
			type =  typeof(obj[property]);
			str += '
(' + type + ') ' + property +
			( (obj[property]==null)?(': null'):('')) + '
';

			// We keep iterating if this property is an Object, non null
			// and we are inside the required number of levels
			if((type == 'object') && (obj[property] != null) && (level+1 < maxLevels))
				str += inspect(obj[property], maxLevels, level+1);
		}
		catch(err)
		{
			// Is there some properties in obj we can't access? Print it red.
			if(typeof(err) == 'string') msg = err;
			else if(err.message)        msg = err.message;
			else if(err.description)    msg = err.description;
			else                        msg = 'Unknown';

			str += '
(Error) ' + property + ': ' + msg +'
';
		}
	}

	// Close indent
	str += '
';

	return str;
}

//--></script>

<commit_msg>Round min and max - for display purposes<commit_after>/**
 Protein Engineering Analysis Tool Structure Analysis (PEATSA)
 Copyright (C) 2010 Michael Johnston & Jens Erik Nielsen

 Author: Michael Johnston

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

 Contact information:
 Email: Jens.Nielsen_at_gmail.com
 Normal mail:
 Jens Nielsen
 SBBS, Conway Institute
 University College Dublin
 Dublin 4, Ireland
 **/

//Functions for coloring the pdb structure displayed in Jmol on the results page
//It requires that JSGetCalculationData.php is included.

//Returns an array containing the data for calculation.
//If calculation is not finished this function returns nil
function dataForCalculation(calculation)
{
	if(calculation == "Stability")
	{
		return create_Stability_data_array();
	}
	else if(calculation == "Scan")
	{
		return create_Scan_data_array();
	}
	else if(calculation == "Binding")
	{
		return create_Binding_data_array();
	}
	else if(calculation == "Modelling")
	{
		return create_Modelling_data_array();
	}
}

Array.prototype.max = function()
{
	var max = this[0];
	var len = this.length;
	for (var i = 1; i < len; i++)
	{
		if (this[i] > max)
		{
			max = this[i];
		}
	}
	return Math.round(max*100)/100;
}

Array.prototype.min = function()
{
	var min = this[0];
	var len = this.length;
	for (var i = 1; i < len; i++)
	{
		if (this[i] < min)
		{
			min = this[i];
		}
	}
	return Math.round(min*100)/100 ;
}

function jmol_array_from_array(data)
{
	var result = "{";
	for(var i=0; i<data.length; i++)
	{
		if(i==0)
		{
			result = result + data[i][1];
			//window.console.log(data[i]);
		}
		else
		{
			result = result + "," + data[i][1];
		}
	}

	result = result + "}";

	return result;
}

//Parse a reduced mutation code ($Chain$ResidueIndex$ResidueCode$MutationCode)
//into a four element array.
function parseMutationCode(code)
{
	//Some pdbs may not have a chain id, so we have to check if one is present
	chain = code.substring(0,1);
	if((parseInt(chain) == 0) || isNaN(parseInt(chain)))
	{
		residueNumber = code.substring(1, code.length - 2);
		residueCode = code.substring(code.length -2, code.length - 1);
		mutationCode = code.substring(code.length -1, code.length);
	}
	else
	{
		chain = "";
		residueNumber = code.substring(0, code.length - 2);
		residueCode = code.substring(code.length -2, code.length - 1);
		mutationCode = code.substring(code.length -1, code.length);
	}

	return new Array(chain, residueNumber, residueCode,  mutationCode);
}

//Function connected to the color structure radio button array
//value is a string indicating how to colour the structure
//the valid values are structure, Scan, Binding, Stability.
//Also sets the min and max scale values.
function colorStructure(value)
{
	if(value == "structure")
	{
		jmolScript('select {*}');
		jmolScript('color ribbon structure;');
		HideContent('Scale');
	}
	else
	{
		var values = new Array();

		//jmolScript('{*}.temperature=0.01');
		jmolScript('color ribbon None');

		list = '(';
		var data = dataForCalculation(value);
		for(var i=0; i<data.length; i++)
		{
			values[i] = parseFloat(data[i][1]);
			//Amazingly you can't set temperature to 0 in Jmol
			//Have to use some small non-zero number
			if(values[i] == 0.0)
			{
				data[i][1] = '0.0000001';
			}
			var script = '.CA}.temperature=';
			var codeData = parseMutationCode(data[i][0]);
			selectionString =  codeData[1];
			if(codeData[0] != "")
	   		{
				selectionString = selectionString + ':' + codeData[0];
	   		}
			script = '{'+ selectionString + script + data[i][1];
			jmolScript(script);
			list = list + selectionString + '.CA';
			if(i != data.length - 1)
				list = list + ',';
		}
		list = list + ')';
		command = 'select ' + list + ';set rangeSelected on; color ribbon relativeTemperature';
		jmolScript(command);

		//Set the scale values
		var min = values.min();
		var max = values.max();
		var mid = (max + min)*0.5;
		//Round to three decimal places
		mid = Math.round(mid*Math.pow(10,3))/Math.pow(10,3);
		document.getElementById('maxvalue').innerHTML = max;
		document.getElementById('minvalue').innerHTML = min;
		document.getElementById('midvalue').innerHTML = mid;
		ShowContent('Scale');
	}
}

//Taken from http://www.codeproject.com/KB/miscctrl/JS_Inspect_Object.aspx
function inspect(obj, maxLevels, level)
{
	var str = '', type, msg;

	// Start Input Validations
	// Don't touch, we start iterating at level zero
	if(level == null)  level = 0;

	// At least you want to show the first level
	if(maxLevels == null) maxLevels = 1;
	if(maxLevels < 1)
		return 'Error: Levels number must be > 0';

	// We start with a non null object
	if(obj == null)
		return 'Error: Object NULL';
	// End Input Validations

	// Each Iteration must be indented
	str += '
';

	// Start iterations for all objects in obj
	for(property in obj)
	{
		try
		{
			// Show "property" and "type property"
			type =  typeof(obj[property]);
			str += '
(' + type + ') ' + property +
			( (obj[property]==null)?(': null'):('')) + '
';

			// We keep iterating if this property is an Object, non null
			// and we are inside the required number of levels
			if((type == 'object') && (obj[property] != null) && (level+1 < maxLevels))
				str += inspect(obj[property], maxLevels, level+1);
		}
		catch(err)
		{
			// Is there some properties in obj we can't access? Print it red.
			if(typeof(err) == 'string') msg = err;
			else if(err.message)        msg = err.message;
			else if(err.description)    msg = err.description;
			else                        msg = 'Unknown';

			str += '
(Error) ' + property + ': ' + msg +'
';
		}
	}

	// Close indent
	str += '
';

	return str;
}

//--></script>

<|endoftext|>


<commit_before>/*
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

var gRule;
var gActions;

function init() {
  gRule = window.arguments[0] || {};
  if (gRule.name) {
    let title = document.documentElement.getAttribute('title-template');
    document.title = title.replace(/%s/i, gRule.name);
  }

  gActions = document.getElementById('actions');

  Object.keys(gRule).forEach(function(aKey) {
    var value = gRule[aKey];
    var field = document.getElementById(aKey + '-field');
    if (field && value)
      field.value = value;
  });

  var actions = [];
  if (gRule.actions) {
    actions = JSON.parse(gRule.actions);
  } else if (gRule.action) {
    actions = [gRule.action];
  }

  actions.forEach(actionAdd);

  onGroupChanged();
  validateName();
}

function validateName() {
  var nameField = document.getElementById('name-field');
  var name = nameField.value;
  var accept = document.documentElement.getButton('accept');
  if (window.opener.isRuleDuplicated(name, gRule)) {
    accept.setAttribute('disabled', true);
    document.documentElement.setAttribute('validation-errors', 'duplicated-name');
    return false;
  } else if (name.trim() === '') {
    accept.setAttribute('disabled', true);
    document.documentElement.setAttribute('validation-errors', 'blank-name');
    return false;
  } else {
    accept.removeAttribute('disabled');
    document.documentElement.removeAttribute('validation-errors');
    return true;
  }
}

function onGroupChanged() {
  var group = document.getElementById('group-field').value;
  document.documentElement.setAttribute('group-type', group);
}

function actionAdd(aAction) {
  var template = document.getElementById('action-item-template');
  var item = template.cloneNode(true);
  item.removeAttribute('id');
  gActions.insertBefore(item, gActions.lastChild);

  aAction = aAction || '';
  var matched = aAction.match(/^([^;]+)(?:;(.*)$)?/);
  if (!matched)
    return;

  var name = matched[1];
  var params = matched[2];
  if (name)
    item.querySelector('.action-name-field').value = name;
  if (params)
    item.querySelector('.action-params-field').value = params;
}

function actionUp(aItem) {
  if (aItem == gActions.firstChild)
    return;
  gActions.insertBefore(aItem, aItem.previousSibling);
}

function actionDown(aItem) {
  if (aItem.nextSibling == gActions.lastChild)
    return;
  gActions.insertBefore(aItem, aItem.nextSibling.nextSibling);
}

function actionDelete(aItem) {
  gActions.removeChild(aItem);
}

function serializeAction(aItem) {
  var nameField = aItem.querySelector('.action-name-field');
  var paramsField = aItem.querySelector('.action-params-field');
  if (paramsField.clientWidth > 0 &&
      paramsField.clientHeight > 0 &&
      paramsField.value) {
    return nameField.value + ';' + paramsField.value;
  } else {
    return nameField.value;
  }
}

function onAccept() {
  ['name',
   'group',
   'type',
   'url',
   'title',
   'text'].forEach(function(aProperty) {
    gRule[aProperty] = document.getElementById(aProperty + '-field').value;
  });
  switch (gRule.group) {
  case 'common':
    gRule.url = '';
    break;
  case 'general':
    gRule.type = '';
    break;
  }

  var actions = document.querySelectorAll('#actions richlistitem.action');
  if (actions.length === 0) {
    gRule.actions = gRule.action = '';
  } else if (actions.length == 1) {
    gRule.actions = '';
    gRule.action = serializeAction(actions[0]);
  } else {
    gRule.action = '';
    gRule.actions = JSON.stringify(Array.map(actions, serializeAction));
  }

  gRule.changed = true;

  return true;
}
<commit_msg>Support basic common dialogs<commit_after>/*
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

var gRule;
var gActions;

function init() {
  gRule = window.arguments[0] || {};
  if (gRule.name) {
    let title = document.documentElement.getAttribute('title-template');
    document.title = title.replace(/%s/i, gRule.name);
  }

  gActions = document.getElementById('actions');

  Object.keys(gRule).forEach(function(aKey) {
    var value = gRule[aKey];
    var field = document.getElementById(aKey + '-field');
    if (field && value)
      field.value = value;
  });

  var actions = [];
  if (gRule.actions) {
    actions = JSON.parse(gRule.actions);
  } else if (gRule.action) {
    actions = [gRule.action];
  }

  actions.forEach(actionAdd);

  onGroupChanged();
  validateName();
}

function validateName() {
  var nameField = document.getElementById('name-field');
  var name = nameField.value;
  var accept = document.documentElement.getButton('accept');
  if (window.opener.isRuleDuplicated(name, gRule)) {
    accept.setAttribute('disabled', true);
    document.documentElement.setAttribute('validation-errors', 'duplicated-name');
    return false;
  } else if (name.trim() === '') {
    accept.setAttribute('disabled', true);
    document.documentElement.setAttribute('validation-errors', 'blank-name');
    return false;
  } else {
    accept.removeAttribute('disabled');
    document.documentElement.removeAttribute('validation-errors');
    return true;
  }
}

function onGroupChanged() {
  var group = document.getElementById('group-field').value;
  document.documentElement.setAttribute('group-type', group);
}

function captureActualOperation(aAction) {
  var type = document.getElementById('type-field');
  console.log(type.value);
  switch (type.value) {
  case 'alert':
    alert();
    actionAdd();
    break;
  case 'confirm':
    var result = confirm();
    console.log(result);
    if (result) {
      actionAdd('accept');
    } else {
      actionAdd('cancel');
    }
    break;
  case 'confirmEx':
    // TODO
    //confirmEx();
    break;
  case 'prompt':
    var result = prompt();
    console.log(result);
    if (result === null) {
      actionAdd('cancel');
    } else {
      actionAdd('input;' + result);
      actionAdd('accept');
    }
    break;
  case 'select':
    // TODO
    //select();
    break;
  }
}

function actionAdd(aAction) {
  var template = document.getElementById('action-item-template');
  var item = template.cloneNode(true);
  item.removeAttribute('id');
  gActions.insertBefore(item, gActions.lastChild);

  aAction = aAction || '';
  var matched = aAction.match(/^([^;]+)(?:;(.*)$)?/);
  if (!matched)
    return;

  var name = matched[1];
  var params = matched[2];
  if (name)
    item.querySelector('.action-name-field').value = name;
  if (params)
    item.querySelector('.action-params-field').value = params;
}

function actionUp(aItem) {
  if (aItem == gActions.firstChild)
    return;
  gActions.insertBefore(aItem, aItem.previousSibling);
}

function actionDown(aItem) {
  if (aItem.nextSibling == gActions.lastChild)
    return;
  gActions.insertBefore(aItem, aItem.nextSibling.nextSibling);
}

function actionDelete(aItem) {
  gActions.removeChild(aItem);
}

function serializeAction(aItem) {
  var nameField = aItem.querySelector('.action-name-field');
  var paramsField = aItem.querySelector('.action-params-field');
  if (paramsField.clientWidth > 0 &&
      paramsField.clientHeight > 0 &&
      paramsField.value) {
    return nameField.value + ';' + paramsField.value;
  } else {
    return nameField.value;
  }
}

function onAccept() {
  ['name',
   'group',
   'type',
   'url',
   'title',
   'text'].forEach(function(aProperty) {
    gRule[aProperty] = document.getElementById(aProperty + '-field').value;
  });
  switch (gRule.group) {
  case 'common':
    gRule.url = '';
    break;
  case 'general':
    gRule.type = '';
    break;
  }

  var actions = document.querySelectorAll('#actions richlistitem.action');
  if (actions.length === 0) {
    gRule.actions = gRule.action = '';
  } else if (actions.length == 1) {
    gRule.actions = '';
    gRule.action = serializeAction(actions[0]);
  } else {
    gRule.action = '';
    gRule.actions = JSON.stringify(Array.map(actions, serializeAction));
  }

  gRule.changed = true;

  return true;
}
<|endoftext|>


<commit_before>// moment.js locale configuration
// locale : russian (ru)
// author : Viktorminator : https://github.com/Viktorminator
// Author : Menelion Elensúle : https://github.com/Oire

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        define(['moment'], factory); // AMD
    } else if (typeof exports === 'object') {
        module.exports = factory(require('../moment')); // Node
    } else {
        factory((typeof global !== undefined ? global : this).moment); // node or other global
    }
}(function (moment) {
    function plural(word, num) {
        var forms = word.split('_');
        return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
    }

    function relativeTimeWithPlural(number, withoutSuffix, key) {
        var format = {
            'mm': withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут',
            'hh': 'час_часа_часов',
            'dd': 'день_дня_дней',
            'MM': 'месяц_месяца_месяцев',
            'yy': 'год_года_лет'
        };
        if (key === 'm') {
            return withoutSuffix ? 'минута' : 'минуту';
        }
        else {
            return number + ' ' + plural(format[key], +number);
        }
    }

    function monthsCaseReplace(m, format) {
        var months = {
            'nominative': 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'),
            'accusative': 'января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря'.split('_')
        },

        nounCase = (/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/).test(format) ?
            'accusative' :
            'nominative';

        return months[nounCase][m.month()];
    }

    function monthsShortCaseReplace(m, format) {
        var monthsShort = {
            'nominative': 'янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек'.split('_'),
            'accusative': 'янв_фев_мар_апр_мая_июня_июля_авг_сен_окт_ноя_дек'.split('_')
        },

        nounCase = (/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/).test(format) ?
            'accusative' :
            'nominative';

        return monthsShort[nounCase][m.month()];
    }

    function weekdaysCaseReplace(m, format) {
        var weekdays = {
            'nominative': 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'),
            'accusative': 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split('_')
        },

        nounCase = (/\[ ?[Вв] ?(?:прошлую|следующую)? ?\] ?dddd/).test(format) ?
            'accusative' :
            'nominative';

        return weekdays[nounCase][m.day()];
    }

    return moment.defineLocale('ru', {
        months : monthsCaseReplace,
        monthsShort : monthsShortCaseReplace,
        weekdays : weekdaysCaseReplace,
        weekdaysShort : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
        weekdaysMin : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
        monthsParse : [/^янв/i, /^фев/i, /^мар/i, /^апр/i, /^ма[й|я]/i, /^июн/i, /^июл/i, /^авг/i, /^сен/i, /^окт/i, /^ноя/i, /^дек/i],
        longDateFormat : {
            LT : 'HH:mm',
            LTS : 'LT:ss',
            L : 'DD.MM.YYYY',
            LL : 'D MMMM YYYY г.',
            LLL : 'D MMMM YYYY г., LT',
            LLLL : 'dddd, D MMMM YYYY г., LT'
        },
        calendar : {
            sameDay: '[Сегодня в] LT',
            nextDay: '[Завтра в] LT',
            lastDay: '[Вчера в] LT',
            nextWeek: function () {
                return this.day() === 2 ? '[Во] dddd [в] LT' : '[В] dddd [в] LT';
            },
            lastWeek: function () {
                switch (this.day()) {
                case 0:
                    return '[В прошлое] dddd [в] LT';
                case 1:
                case 2:
                case 4:
                    return '[В прошлый] dddd [в] LT';
                case 3:
                case 5:
                case 6:
                    return '[В прошлую] dddd [в] LT';
                }
            },
            sameElse: 'L'
        },
        relativeTime : {
            future : 'через %s',
            past : '%s назад',
            s : 'несколько секунд',
            m : relativeTimeWithPlural,
            mm : relativeTimeWithPlural,
            h : 'час',
            hh : relativeTimeWithPlural,
            d : 'день',
            dd : relativeTimeWithPlural,
            M : 'месяц',
            MM : relativeTimeWithPlural,
            y : 'год',
            yy : relativeTimeWithPlural
        },

        meridiemParse: /ночи|утра|дня|вечера/i,
        isPM : function (input) {
            return /^(дня|вечера)$/.test(input);
        },

        meridiem : function (hour, minute, isLower) {
            if (hour < 4) {
                return 'ночи';
            } else if (hour < 12) {
                return 'утра';
            } else if (hour < 17) {
                return 'дня';
            } else {
                return 'вечера';
            }
        },

        ordinalParse: /\d{1,2}-(й|го|я)/,
        ordinal: function (number, period) {
            switch (period) {
            case 'M':
            case 'd':
            case 'DDD':
                return number + '-й';
            case 'D':
                return number + '-го';
            case 'w':
            case 'W':
                return number + '-я';
            default:
                return number;
            }
        },

        week : {
            dow : 1, // Monday is the first day of the week.
            doy : 7  // The week that contains Jan 1st is the first week of the year.
        }
    });
}));
<commit_msg>alter Russian locale<commit_after>// moment.js locale configuration
// locale : russian (ru)
// author : Viktorminator : https://github.com/Viktorminator
// Author : Menelion Elensúle : https://github.com/Oire

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        define(['moment'], factory); // AMD
    } else if (typeof exports === 'object') {
        module.exports = factory(require('../moment')); // Node
    } else {
        factory((typeof global !== undefined ? global : this).moment); // node or other global
    }
}(function (moment) {
    function plural(word, num) {
        var forms = word.split('_');
        return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);
    }

    function relativeTimeWithPlural(number, withoutSuffix, key) {
        var format = {
            'mm': withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут',
            'hh': 'час_часа_часов',
            'dd': 'день_дня_дней',
            'MM': 'месяц_месяца_месяцев',
            'yy': 'год_года_лет'
        };
        if (key === 'm') {
            return withoutSuffix ? 'минута' : 'минуту';
        }
        else {
            return number + ' ' + plural(format[key], +number);
        }
    }

    function monthsCaseReplace(m, format) {
        var months = {
            'nominative': 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'),
            'accusative': 'января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря'.split('_')
        },

        nounCase = (/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/).test(format) ?
            'accusative' :
            'nominative';

        return months[nounCase][m.month()];
    }

    function monthsShortCaseReplace(m, format) {
        var monthsShort = {
            'nominative': 'янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек'.split('_'),
            'accusative': 'янв_фев_мар_апр_мая_июня_июля_авг_сен_окт_ноя_дек'.split('_')
        },

        nounCase = (/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/).test(format) ?
            'accusative' :
            'nominative';

        return monthsShort[nounCase][m.month()];
    }

    function weekdaysCaseReplace(m, format) {
        var weekdays = {
            'nominative': 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'),
            'accusative': 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split('_')
        },

        nounCase = (/\[ ?[Вв] ?(?:прошлую|следующую)? ?\] ?dddd/).test(format) ?
            'accusative' :
            'nominative';

        return weekdays[nounCase][m.day()];
    }

    return moment.defineLocale('ru', {
        months : monthsCaseReplace,
        monthsShort : monthsShortCaseReplace,
        weekdays : weekdaysCaseReplace,
        weekdaysShort : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
        weekdaysMin : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
        monthsParse : [/^янв/i, /^фев/i, /^мар/i, /^апр/i, /^ма[й|я]/i, /^июн/i, /^июл/i, /^авг/i, /^сен/i, /^окт/i, /^ноя/i, /^дек/i],
        longDateFormat : {
            LT : 'HH:mm',
            LTS : 'LT:ss',
            L : 'DD.MM.YYYY',
            LL : 'D MMMM YYYY г.',
            LLL : 'D MMMM YYYY г., LT',
            LLLL : 'dddd, D MMMM YYYY г., LT'
        },
        calendar : {
            sameDay: '[Сегодня в] LT',
            nextDay: '[Завтра в] LT',
            lastDay: '[Вчера в] LT',
            nextWeek: function () {
                return this.day() === 2 ? '[Во] dddd [в] LT' : '[В] dddd [в] LT';
            },
            lastWeek: function (now) {
                if (now.week() !== this.week()) {
                    switch (this.day()) {
                    case 0:
                        return '[В прошлое] dddd [в] LT';
                    case 1:
                    case 2:
                    case 4:
                        return '[В прошлый] dddd [в] LT';
                    case 3:
                    case 5:
                    case 6:
                        return '[В прошлую] dddd [в] LT';
                    }
                } else {
                    switch (this.day()) {
                    case 0:
                        return '[В это] dddd [в] LT';
                    case 1:
                    case 2:
                    case 4:
                        return '[В этот] dddd [в] LT';
                    case 3:
                    case 5:
                    case 6:
                        return '[В эту] dddd [в] LT';
                    }
                }
            },
            sameElse: 'L'
        },
        relativeTime : {
            future : 'через %s',
            past : '%s назад',
            s : 'несколько секунд',
            m : relativeTimeWithPlural,
            mm : relativeTimeWithPlural,
            h : 'час',
            hh : relativeTimeWithPlural,
            d : 'день',
            dd : relativeTimeWithPlural,
            M : 'месяц',
            MM : relativeTimeWithPlural,
            y : 'год',
            yy : relativeTimeWithPlural
        },

        meridiemParse: /ночи|утра|дня|вечера/i,
        isPM : function (input) {
            return /^(дня|вечера)$/.test(input);
        },

        meridiem : function (hour, minute, isLower) {
            if (hour < 4) {
                return 'ночи';
            } else if (hour < 12) {
                return 'утра';
            } else if (hour < 17) {
                return 'дня';
            } else {
                return 'вечера';
            }
        },

        ordinalParse: /\d{1,2}-(й|го|я)/,
        ordinal: function (number, period) {
            switch (period) {
            case 'M':
            case 'd':
            case 'DDD':
                return number + '-й';
            case 'D':
                return number + '-го';
            case 'w':
            case 'W':
                return number + '-я';
            default:
                return number;
            }
        },

        week : {
            dow : 1, // Monday is the first day of the week.
            doy : 7  // The week that contains Jan 1st is the first week of the year.
        }
    });
}));
<|endoftext|>


<commit_before>const React = require('react');

const Code = require('components/Code');
const Markdown = require('components/Markdown');

class RestrictFocusToChildrenDocs extends React.Component {
  render () {
    return (

          Restrict Focus To Children
          Wrapper that restricts focus to it's children

Demo

          See Demo of Drawer, Modal, SimpleSelect, or DateRangePicker components to see how focus is trapped when popover content is shown.

Usage

          When mounted, the RestrictFocusToChildren component only allows focus on nodes that are focusable and are children of itself. This is useful for a11y in popover content such as modals and dialogs.

          In the example below, the Outter Content Button would not be focusable once the RestrictFocusToChildren component mounted.

Example

        <Markdown>
          {`

              <button onClick={() => this.setState({ showTrappedContent: true })}>
                Outter Content Button
              </button>
              {this.state.showTrappedContent ? (
                <RestrictFocusToChildren>
                  <button onClick={() => this.setState({ showTrappedContent: false })}>
                    Inner Content Button
                  </button>
                </RestrictFocusToChildren>
              ) : null}

          `}
        </Markdown>

    );
  }
}

module.exports = RestrictFocusToChildrenDocs;
<commit_msg>Add clarity to RestrictFocusToChildrenDocs<commit_after>const React = require('react');

const Code = require('components/Code');
const Markdown = require('components/Markdown');

class RestrictFocusToChildrenDocs extends React.Component {
  render () {
    return (

          Restrict Focus To Children
          Wrapper that restricts focus to it's children

Demo

          See Demo of Drawer, Modal, SimpleSelect, or DateRangePicker components to see how focus is trapped when popover content is shown.

Usage

          When mounted, the RestrictFocusToChildren component only allows focus on nodes that are focusable and are children of itself. This is useful for a11y in popover content such as modals and dialogs.

          In the example below, the Outter Content Button would not be focusable once the RestrictFocusToChildren component mounted but would become focusable again once RestrictFocusToChildren un-mounted.

Example

        <Markdown>
          {`

              <button onClick={() => this.setState({ showTrappedContent: true })}>
                Outter Content Button
              </button>
              {this.state.showTrappedContent ? (
                <RestrictFocusToChildren>
                  <button onClick={() => this.setState({ showTrappedContent: false })}>
                    Inner Content Button
                  </button>
                </RestrictFocusToChildren>
              ) : null}

          `}
        </Markdown>

    );
  }
}

module.exports = RestrictFocusToChildrenDocs;
<|endoftext|>


<commit_before>;(function(ctx) {

    // These ranges will get used
    // to 'automaticly' create the specific
    // methods and options.
    var RANGES = {
        secondly: 1000,
        minutely: 60000,
        quarterly: 900000,
        hourly: 3600000,
        daily: 86400000,
        weekly: 604800000
    };

    var RuleChain = function(opts) {
        this.options = opts || {};

        // In the 'track' array we save the
        // timestamps of each call in history
        // and the future. We need to store this
        // information, otherwise we would not be
        // able to calculate which delay the next call
        // should have.
        this.track = this.options.history || [];

        this.rules = [];

        // Auto-Create the timerange options
        for (var name in RANGES) {
            if (!RANGES.hasOwnProperty(name)) continue;
            if (name in this.options) this[name](this.options[name]);
        }
    };

    // Determinate when the next call can be made.
    // Returns an delay in milliseconds
    RuleChain.prototype.getNextDelay = function() {
        return this._runRules().delay;
    };

    // Push a function into the call stack.
    // Optionally a second conditional function
    // can get passed in. The conditional function gets an 'delay'
    // parameter passed in as first argument which indicates
    // after how many milliseconds fn will get called.
    // Returning false in the conditional function prevents
    // fn from being added to the call stack.
    RuleChain.prototype.push = function(fn, cond) {
        var delay = this.getNextDelay(),
            that = this;

        if (!this.rules.length) {
            throw {
                name: 'RuleError',
                message: 'there are no defined rules'
            };
        }

        if (typeof cond === 'function' && cond(delay) === false) {
            return false;
        }

        this.track.push(Date.now() + delay);

        return {
            delay: delay,
            timer: setTimeout(function() {
                // Call the 'onCall' Callback if an entry
                // gets added to the history.
                if (typeof that.options.onCall === 'function') {
                    that.options.onCall(delay);
                }
                fn();
            }, delay)
        };
    };

    // Run through all rules and determinate when
    // the next call can be made. Each rule
    // also returns also a property 'spliceIdx'.
    // spliceIdx indicates from which index
    // on the track array can be safely cleared.
    RuleChain.prototype._runRules = function() {
        var est = (function(memo, rules, track) {
            var now = Date.now();

            for (var i = 0, len = rules.length; i < len; i++) {
                (function(fn) {
                    var comp = fn(now, track);
                    if (memo.delay < comp.delay) {
                        memo.delay = comp.delay
                    }

                    if (!('spliceIdx' in memo) || memo.spliceIdx > comp.spliceIdx) {
                        memo.spliceIdx = comp.spliceIdx
                    }
                })(rules[i]);
            }

            return memo;
        })({
            delay: 0
        }, this.rules, this.track);

        if (('spliceIdx' in est) && est.spliceIdx > 0) {
            if (typeof this.options.onClear === 'function') {
                this.options.onClear(this.track[est.spliceIdx]);
            }
            this.track.splice(0, est.spliceIdx);
        }

        return est;
    };

    // inspired by _.sortedIndex
    // find the position in the sorted
    // array 'this.track' where 'val'
    // could be inserted
    RuleChain.prototype._getInsertPosition = function(val) {
        var low = 0, high = this.track.length;
        while (low < high) {
            var mid = (low + high) >>> 1;
            this.track[mid] < val ? low = mid + 1 : high = mid;
        }
        return low;
    };

    // Register a new rule which indicates that within
    // a period of 'millis' only a certain amount
    // of 'maxcalls' can be made.
    RuleChain.prototype.within = function(millis, maxcalls) {
        var that = this;

        // check if maxcalls is an integer and
        // it is greater than 0
        if (maxcalls % 1 !== 0 || maxcalls < 1) {
            throw {
                name: 'MaxcallsRangeError',
                message: 'maxcalls must be above 0 and an integer'
            };
        }

        this.register(function(now, track) {
            var past = now - millis,
                idx = that._getInsertPosition(past),
                rest = track.length - idx,
                delay = (rest >= maxcalls) ? (track[idx + (rest - maxcalls)] + millis) - now : 0;
            return {
                delay: delay,
                spliceIdx: idx
            };
        });

        return this;
    };

    // Create some methods out of our RANGES Object
    for (var name in RANGES) {
        if (!RANGES.hasOwnProperty(name)) continue;
        (function(name, millis) {
            RuleChain.prototype[name] = function(maxcalls) {
                return this.within(millis, maxcalls);
            }
        })(name, RANGES[name]);
    }

    // Register a custom rule.
    RuleChain.prototype.register = function(fn) {
        this.rules.push(fn);
        return this;
    };

    // This is basically just a factory
    // to create new RuleChains
    var limits = function(opts) {
        return new RuleChain(opts);
    };

    limits.RuleChain = RuleChain;

    // Node.js / browserify
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = limits;
    }
    // AMD
    else if (typeof define !== 'undefined' && define.amd) {
        define([], function () {
            return limits;
        });
    }
    // <script>
    else {
        ctx.limits = limits;
    }

})(this);<commit_msg>some refactoring<commit_after>;(function(ctx) {

    // These ranges will get used
    // to 'automaticly' create the specific
    // methods and options.
    var RANGES = {
        secondly: 1000,
        minutely: 60000,
        quarterly: 900000,
        hourly: 3600000,
        daily: 86400000,
        weekly: 604800000
    };

    var RuleChain = function(opts) {
        this.options = opts || {};

        // In the 'track' array we save the
        // timestamps of each call in history
        // and the future. We need to store this
        // information, otherwise we would not be
        // able to calculate which delay the next call
        // should have.
        this.track = this.options.history || [];

        this.rules = [];

        // Auto-Create the timerange options
        for (var name in RANGES) {
            if (!RANGES.hasOwnProperty(name)) continue;
            if (name in this.options) this[name](this.options[name]);
        }
    };

    // Determinate when the next call can be made.
    // Returns an delay in milliseconds
    RuleChain.prototype.getNextDelay = function() {
        return this._runRules().delay;
    };

    // Push a function into the call stack.
    // Optionally a second conditional function
    // can get passed in. The conditional function gets an 'delay'
    // parameter passed in as first argument which indicates
    // after how many milliseconds fn will get called.
    // Returning false in the conditional function prevents
    // fn from being added to the call stack.
    RuleChain.prototype.push = function(fn, cond) {
        var delay = this.getNextDelay(),
            that = this;

        if (!this.rules.length) {
            throw {
                name: 'RuleError',
                message: 'there are no defined rules'
            };
        }

        if (typeof cond === 'function' && cond(delay) === false) {
            return false;
        }

        this.track.push(Date.now() + delay);

        return {
            delay: delay,
            timer: setTimeout(function() {
                // Call the 'onCall' Callback if an entry
                // gets added to the history.
                if (typeof that.options.onCall === 'function') {
                    that.options.onCall(delay);
                }
                fn();
            }, delay)
        };
    };

    // Run through all rules and determinate when
    // the next call can be made. Each rule
    // also returns also a property 'spliceIdx'.
    // spliceIdx indicates from which index
    // on the track array can be safely cleared.
    RuleChain.prototype._runRules = function() {
        var now = Date.now(),
            memo = {
                delay: 0
            };

        for (var i = 0, len = this.rules.length; i < len; i++) {
            var comp = this.rules[i](now, this.track);

            if (memo.delay < comp.delay) {
                memo.delay = comp.delay
            }

            if (!('spliceIdx' in memo) || memo.spliceIdx > comp.spliceIdx) {
                memo.spliceIdx = comp.spliceIdx
            }
        }

        if (('spliceIdx' in memo) && memo.spliceIdx > 0) {
            if (typeof this.options.onClear === 'function') {
                this.options.onClear(this.track[memo.spliceIdx]);
            }
            this.track.splice(0, memo.spliceIdx);
        }

        return memo;
    };

    // inspired by _.sortedIndex
    // find the position in the sorted
    // array 'this.track' where 'val'
    // could be inserted
    RuleChain.prototype._getInsertPosition = function(val) {
        var low = 0,
            high = this.track.length;

        while (low < high) {
            var mid = (low + high) >>> 1;
            this.track[mid] < val ? low = mid + 1 : high = mid;
        }

        return low;
    };

    // Register a new rule which indicates that within
    // a period of 'millis' only a certain amount
    // of 'maxcalls' can be made.
    RuleChain.prototype.within = function(millis, maxcalls) {
        var that = this;

        // check if maxcalls is an integer and
        // it is greater than 0
        if (maxcalls % 1 !== 0 || maxcalls < 1) {
            throw {
                name: 'MaxcallsRangeError',
                message: 'maxcalls must be above 0 and an integer'
            };
        }

        this.register(function(now, track) {
            var past = now - millis,
                idx = that._getInsertPosition(past),
                rest = track.length - idx,
                delay = (rest >= maxcalls) ? (track[idx + (rest - maxcalls)] + millis) - now : 0;

            return {
                delay: delay,
                spliceIdx: idx
            };
        });

        return this;
    };

    // Create some methods out of our RANGES Object
    for (var name in RANGES) {
        if (!RANGES.hasOwnProperty(name)) continue;
        (function(name) {
            RuleChain.prototype[name] = function(maxcalls) {
                return this.within(RANGES[name], maxcalls);
            }
        })(name);
    }

    // Register a custom rule.
    RuleChain.prototype.register = function(fn) {
        this.rules.push(fn);
        return this;
    };

    // This is basically just a factory
    // to create new RuleChains
    var limits = function(opts) {
        return new RuleChain(opts);
    };

    limits.RuleChain = RuleChain;

    // Node.js / browserify
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = limits;
    }
    // AMD
    else if (typeof define !== 'undefined' && define.amd) {
        define([], function () {
            return limits;
        });
    }
    // <script>
    else {
        ctx.limits = limits;
    }

})(this);<|endoftext|>