<commit_before>(function (maxWait,plstype){

    var self = this,
        downloaded = false,
        playlistEntries={},
        format = plstype,
        dialog;

    this.totalWait = 0;
    this.totalWaitSinceChange = 0;
    this.totalSongs = 0;

    this.quoteEscape = function(text) {
        return '"'+text.replace('"','""')+'"';
    };

    this.scrape = function() {
        var playlist = document.querySelectorAll('.song-table tr.song-row');
        for (var i = 0; i < playlist.length; i++) {
            var l = playlist[i],
                title = l.querySelectorAll('td[data-col="title"] .content')[0].textContent,
                artist = l.querySelectorAll('td[data-col="artist"] .content')[0].textContent,
                album = l.querySelectorAll('td[data-col="album"] .content')[0].textContent,
                duration = l.querySelectorAll('td[data-col="duration"] span')[0].textContent,
                lineFormat;
            if (self.format == 'ivy') {
                lineFormat = artist.replace('-', ' ').trim() + ' - ' + title.replace(/(.+?)\s*[\(\[].+[\)\]]\s*$/, '$1').trim();
            } else if (self.format == 'm3u') {
                var durationParts = duration.split(':'),
                    totalSeconds;

                if (durationParts.length === 3) {
                    totalSeconds = parseInt(durationParts[0],10) * 3600 + parseInt(durationParts[1],10) * 60 + parseInt(durationParts[2],10);
                } else if (durationParts.length == 2) {
                    totalSeconds = parseInt(durationParts[0],10) * 60 + parseInt(durationParts[1],10);
                } else {
                    totalSeconds = -1;
                }

                lineFormat = '#EXTINF:' + totalSeconds + ','
                    + artist.replace('-', ' ').trim()
                    + ' - '
                    + title.replace(/(.+?)\s*[\(\[].+[\)\]]\s*$/, '$1').trim()
                    + "\n"
                    + album.trim()
                    + '/'
                    + artist.replace('-', ' ').trim()
                    + ' - '
                    + title.replace(/(.+?)\s*[\(\[].+[\)\]]\s*$/, '$1').trim()
                    + '.mp3'
            } else {
                lineFormat = quoteEscape(artist)+','+quoteEscape(title)+','+quoteEscape(album)+','+quoteEscape(duration);
            }
            if (!playlistEntries.hasOwnProperty(lineFormat)) {
                self.totalSongs++;
                self.totalWaitSinceChange = 0;
                playlistEntries[lineFormat] = {
                    artist: artist,
                    title: title,
                    album: album,
                    duration: duration
                }
            }
        }
    };

    this.download = function() {
        if (downloaded) return;
        downloaded = true;
        var csvContent,
            downloadAnchor,
            downloadBlob,
            type,
            filename;
        csvContent = '';
        for (var line in playlistEntries) {
            csvContent += line + "\n";
        }
        if (self.format == 'ivy') {
            type = 'text';
            filename = 'playlist.txt';
        } else if (self.format == 'm3u') {
            csvContent = "#EXTM3U\n" + csvContent;
            type = 'text/m3u';
            filename = 'playlist.m3u';
        } else {
            type = 'text/csv';
            filename = 'playlist.csv';
        }
        downloadAnchor = document.createElement('a');
        downloadBlob = new Blob([csvContent], {'type': type});
        downloadAnchor.href = window.URL.createObjectURL(downloadBlob);
        downloadAnchor.download = filename;
        downloadAnchor.click();
    };

    this.scrollAll = function() {
        self.scrape();
        if (downloaded) {
            return;
        }
        var timeUntilDownload = maxWait >= 0 ? maxWait*1000 - self.totalWait: 9000 - self.totalWaitSinceChange;
        if (timeUntilDownload > 0) {
            self.totalWait += 50; // close enough
            self.totalWaitSinceChange += 50;
            self.statusBox.innerHTML = 'Download in ' + Math.round(timeUntilDownload/1000) + ' seconds; Songs: ' + self.totalSongs;
            setTimeout(function(){self.scrollAll();}, 50);
        } else {
            download();
        }
    };

    this.begin = function() {
        self.dialog.close();
        var playlistSelect = document.getElementById('playlist-format');
        self.format = playlistSelect.options[playlistSelect.selectedIndex].value;
        self.scrape();
        self.scrollAll();
        return false;
    };

    self.totalSongs = 0;
    self.statusBox = document.createElement('div');
    self.statusBox.style.position = 'fixed';
    self.statusBox.style.bottom = '0';
    self.statusBox.style.right = '0';
    self.statusBox.style.background = '#CCC';
    self.statusBox.style.zIndex = 999999;
    self.statusBox.innerHTML = 'Songs: 0';
    document.body.appendChild(self.statusBox);

    if (plstype === 'prompt') {
        self.dialog = document.createElement('dialog');
        self.dialog.innerHTML = '<form onsubmit="return self.begin()">Select Format:<select id="playlist-format">'
            +'<option value="m3u">M3U (Generic, soundiiz.com, etc.)</option>'
            +'<option value="csv">CSV (Generic CSV)</option>'
            +'<option value="ivy">IVY (ivyishere.org)</option>'
            +'</select> <input type="submit" value="Begin"/></dialog>';
        document.body.appendChild(self.dialog);
        self.dialog.showModal();
    } else {
        self.begin();
    }

})(-1,'prompt');
<commit_msg>Update content inspection to use column-content<commit_after>(function (maxWait,plstype){

    var self = this,
        downloaded = false,
        playlistEntries={},
        format = plstype,
        dialog;

    this.totalWait = 0;
    this.totalWaitSinceChange = 0;
    this.totalSongs = 0;

    this.quoteEscape = function(text) {
        return '"'+text.replace('"','""')+'"';
    };

    this.scrape = function() {
        var playlist = document.querySelectorAll('.song-table tr.song-row');
        for (var i = 0; i < playlist.length; i++) {
            var l = playlist[i],
                title = l.querySelectorAll('td[data-col="title"] .column-content')[0].textContent,
                artist = l.querySelectorAll('td[data-col="artist"] .column-content')[0].textContent,
                album = l.querySelectorAll('td[data-col="album"] .column-content')[0].textContent,
                duration = l.querySelectorAll('td[data-col="duration"] span')[0].textContent,
                lineFormat;
            if (self.format == 'ivy') {
                lineFormat = artist.replace('-', ' ').trim() + ' - ' + title.replace(/(.+?)\s*[\(\[].+[\)\]]\s*$/, '$1').trim();
            } else if (self.format == 'm3u') {
                var durationParts = duration.split(':'),
                    totalSeconds;

                if (durationParts.length === 3) {
                    totalSeconds = parseInt(durationParts[0],10) * 3600 + parseInt(durationParts[1],10) * 60 + parseInt(durationParts[2],10);
                } else if (durationParts.length == 2) {
                    totalSeconds = parseInt(durationParts[0],10) * 60 + parseInt(durationParts[1],10);
                } else {
                    totalSeconds = -1;
                }

                lineFormat = '#EXTINF:' + totalSeconds + ','
                    + artist.replace('-', ' ').trim()
                    + ' - '
                    + title.replace(/(.+?)\s*[\(\[].+[\)\]]\s*$/, '$1').trim()
                    + "\n"
                    + album.trim()
                    + '/'
                    + artist.replace('-', ' ').trim()
                    + ' - '
                    + title.replace(/(.+?)\s*[\(\[].+[\)\]]\s*$/, '$1').trim()
                    + '.mp3'
            } else {
                lineFormat = quoteEscape(artist)+','+quoteEscape(title)+','+quoteEscape(album)+','+quoteEscape(duration);
            }
            if (!playlistEntries.hasOwnProperty(lineFormat)) {
                self.totalSongs++;
                self.totalWaitSinceChange = 0;
                playlistEntries[lineFormat] = {
                    artist: artist,
                    title: title,
                    album: album,
                    duration: duration
                }
            }
        }
    };

    this.download = function() {
        if (downloaded) return;
        downloaded = true;
        var csvContent,
            downloadAnchor,
            downloadBlob,
            type,
            filename;
        csvContent = '';
        for (var line in playlistEntries) {
            csvContent += line + "\n";
        }
        if (self.format == 'ivy') {
            type = 'text';
            filename = 'playlist.txt';
        } else if (self.format == 'm3u') {
            csvContent = "#EXTM3U\n" + csvContent;
            type = 'text/m3u';
            filename = 'playlist.m3u';
        } else {
            type = 'text/csv';
            filename = 'playlist.csv';
        }
        downloadAnchor = document.createElement('a');
        downloadBlob = new Blob([csvContent], {'type': type});
        downloadAnchor.href = window.URL.createObjectURL(downloadBlob);
        downloadAnchor.download = filename;
        downloadAnchor.click();
    };

    this.scrollAll = function() {
        self.scrape();
        if (downloaded) {
            return;
        }
        var timeUntilDownload = maxWait >= 0 ? maxWait*1000 - self.totalWait: 9000 - self.totalWaitSinceChange;
        if (timeUntilDownload > 0) {
            self.totalWait += 50; // close enough
            self.totalWaitSinceChange += 50;
            self.statusBox.innerHTML = 'Download in ' + Math.round(timeUntilDownload/1000) + ' seconds; Songs: ' + self.totalSongs;
            setTimeout(function(){self.scrollAll();}, 50);
        } else {
            download();
        }
    };

    this.begin = function() {
        self.dialog.close();
        var playlistSelect = document.getElementById('playlist-format');
        self.format = playlistSelect.options[playlistSelect.selectedIndex].value;
        self.scrape();
        self.scrollAll();
        return false;
    };

    self.totalSongs = 0;
    self.statusBox = document.createElement('div');
    self.statusBox.style.position = 'fixed';
    self.statusBox.style.bottom = '0';
    self.statusBox.style.right = '0';
    self.statusBox.style.background = '#CCC';
    self.statusBox.style.zIndex = 999999;
    self.statusBox.innerHTML = 'Songs: 0';
    document.body.appendChild(self.statusBox);

    if (plstype === 'prompt') {
        self.dialog = document.createElement('dialog');
        self.dialog.innerHTML = '<form onsubmit="return self.begin();">Select Format:<select id="playlist-format">'
            +'<option value="m3u">M3U (Generic, soundiiz.com, etc.)</option>'
            +'<option value="csv">CSV (Generic CSV)</option>'
            +'<option value="ivy">IVY (ivyishere.org)</option>'
            +'</select> <input type="submit" value="Begin"/></form>';
        document.body.appendChild(self.dialog);
        self.dialog.showModal();
    } else {
        self.begin();
    }

})(-1,'prompt');
<|endoftext|>


<commit_before>// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

const path = require('path');
const fs = require('fs-extra');
const Handlebars = require('handlebars');
const Build = require('@jupyterlab/builder').Build;
const webpack = require('webpack');
const merge = require('webpack-merge').default;
const baseConfig = require('@jupyterlab/builder/lib/webpack.config.base');
const { ModuleFederationPlugin } = webpack.container;

const packageData = require('./package.json');

// Handle the extensions.
const jlab = packageData.jupyterlab;

// Create a list of application extensions and mime extensions from
// jlab.extensions
const extensions = {};
const mimeExtensions = {};

for (const key of jlab.extensions) {
  const {
    jupyterlab: { extension, mimeExtension }
  } = require(`${key}/package.json`);
  if (extension !== undefined) {
    extensions[key] = extension === true ? '' : extension;
  }
  if (mimeExtension !== undefined) {
    mimeExtensions[key] = mimeExtension === true ? '' : mimeExtension;
  }
}

const extensionPackages = jlab.extensions;

// Ensure a clean directory.
function clean(dir) {
  if (fs.existsSync(dir)) {
    fs.removeSync(dir);
  }
  fs.ensureDirSync(dir);
}

const buildDir = path.resolve(jlab.buildDir);
clean(buildDir);

const outputDir = path.resolve(jlab.outputDir);
clean(outputDir);

const schemaDir = path.resolve(jlab.schemaDir);
// ensureAssets puts schemas in the schemas subdirectory
clean(path.join(schemaDir, 'schemas'));

const themeDir = path.resolve(jlab.themeDir);
// ensureAssets puts themes in the themes subdirectory
clean(path.join(themeDir, 'themes'));

// Configuration to handle extension assets
const extensionAssetConfig = Build.ensureAssets({
  packageNames: extensionPackages,
  output: buildDir,
  schemaOutput: schemaDir,
  themeOutput: themeDir
});

// Create the entry point and other assets in build directory.
const source = fs.readFileSync('index.template.js').toString();
const template = Handlebars.compile(source);
const extData = {
  jupyterlab_extensions: extensions,
  jupyterlab_mime_extensions: mimeExtensions
};

fs.writeFileSync(path.join(buildDir, 'index.js'), template(extData));

// Create the bootstrap file that loads federated extensions and calls the
// initialization logic in index.js
const entryPoint = path.join(buildDir, 'bootstrap.js');
fs.copySync('./bootstrap.js', entryPoint);

function createShared(packageData) {
  // Set up module federation sharing config
  const shared = {};
  const extensionPackages = packageData.jupyterlab.extensions;

  // Make sure any resolutions are shared
  for (let [pkg, requiredVersion] of Object.entries(packageData.resolutions)) {
    shared[pkg] = { requiredVersion };
  }

  // Add any extension packages that are not in resolutions (i.e., installed from npm)
  for (let pkg of extensionPackages) {
    if (!shared[pkg]) {
      shared[pkg] = {
        requiredVersion: require(`${pkg}/package.json`).version
      };
    }
  }

  // Add dependencies and sharedPackage config from extension packages if they
  // are not already in the shared config. This means that if there is a
  // conflict, the resolutions package version is the one that is shared.
  const extraShared = [];
  for (let pkg of extensionPackages) {
    let pkgShared = {};
    let {
      dependencies = {},
      jupyterlab: { sharedPackages = {} } = {}
    } = require(`${pkg}/package.json`);
    for (let [dep, requiredVersion] of Object.entries(dependencies)) {
      if (!shared[dep]) {
        pkgShared[dep] = { requiredVersion };
      }
    }

    // Overwrite automatic dependency sharing with custom sharing config
    for (let [dep, config] of Object.entries(sharedPackages)) {
      if (config === false) {
        delete pkgShared[dep];
      } else {
        if ('bundled' in config) {
          config.import = config.bundled;
          delete config.bundled;
        }
        pkgShared[dep] = config;
      }
    }
    extraShared.push(pkgShared);
  }

  // Now merge the extra shared config
  const mergedShare = {};
  for (let sharedConfig of extraShared) {
    for (let [pkg, config] of Object.entries(sharedConfig)) {
      // Do not override the basic share config from resolutions
      if (shared[pkg]) {
        continue;
      }

      // Add if we haven't seen the config before
      if (!mergedShare[pkg]) {
        mergedShare[pkg] = config;
        continue;
      }

      // Choose between the existing config and this new config. We do not try
      // to merge configs, which may yield a config no one wants
      let oldConfig = mergedShare[pkg];

      // if the old one has import: false, use the new one
      if (oldConfig.import === false) {
        mergedShare[pkg] = config;
      }
    }
  }

  Object.assign(shared, mergedShare);

  // Transform any file:// requiredVersion to the version number from the
  // imported package. This assumes (for simplicity) that the version we get
  // importing was installed from the file.
  for (let [pkg, { requiredVersion }] of Object.entries(shared)) {
    if (requiredVersion && requiredVersion.startsWith('file:')) {
      shared[pkg].requiredVersion = require(`${pkg}/package.json`).version;
    }
  }

  // Add singleton package information
  for (let pkg of packageData.jupyterlab.singletonPackages) {
    shared[pkg].singleton = true;
  }

  return shared;
}

const plugins = [
  new ModuleFederationPlugin({
    library: {
      type: 'var',
      name: ['_JUPYTERLAB', 'CORE_LIBRARY_FEDERATION']
    },
    name: 'CORE_FEDERATION',
    shared: createShared(packageData)
  })
];

module.exports = [
  merge(baseConfig, {
    mode: 'development',
    devtool: 'source-map',
    entry: ['./publicpath.js', entryPoint],
    output: {
      path: path.resolve(outputDir),
      library: {
        type: 'var',
        name: ['_JUPYTERLAB', 'CORE_OUTPUT']
      },
      filename: 'bundle.js'
    },
    optimization: {
      splitChunks: {
        chunks: 'all',
        cacheGroups: {
          jlab_core: {
            test: /[\\/]node_modules[\\/]@(jupyterlab|lumino)[\\/]/,
            name: 'jlab_core'
          }
        }
      }
    },
    plugins
  })
].concat(extensionAssetConfig);

// For debugging, write the config out
const logPath = path.join(buildDir, 'build_log.json');
fs.writeFileSync(logPath, JSON.stringify(module.exports, null, '  '));
<commit_msg>Add comments about variable names.<commit_after>// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

const path = require('path');
const fs = require('fs-extra');
const Handlebars = require('handlebars');
const Build = require('@jupyterlab/builder').Build;
const webpack = require('webpack');
const merge = require('webpack-merge').default;
const baseConfig = require('@jupyterlab/builder/lib/webpack.config.base');
const { ModuleFederationPlugin } = webpack.container;

const packageData = require('./package.json');

// Handle the extensions.
const jlab = packageData.jupyterlab;

// Create a list of application extensions and mime extensions from
// jlab.extensions
const extensions = {};
const mimeExtensions = {};

for (const key of jlab.extensions) {
  const {
    jupyterlab: { extension, mimeExtension }
  } = require(`${key}/package.json`);
  if (extension !== undefined) {
    extensions[key] = extension === true ? '' : extension;
  }
  if (mimeExtension !== undefined) {
    mimeExtensions[key] = mimeExtension === true ? '' : mimeExtension;
  }
}

const extensionPackages = jlab.extensions;

// Ensure a clean directory.
function clean(dir) {
  if (fs.existsSync(dir)) {
    fs.removeSync(dir);
  }
  fs.ensureDirSync(dir);
}

// buildDir is a temporary directory where files are copied before the build.
const buildDir = path.resolve(jlab.buildDir);
clean(buildDir);

// outputDir is where the final built assets go
const outputDir = path.resolve(jlab.outputDir);
clean(outputDir);

// <schemaDir>/schemas is where the settings schemas live
const schemaDir = path.resolve(jlab.schemaDir || outputDir);
// ensureAssets puts schemas in the schemas subdirectory
clean(path.join(schemaDir, 'schemas'));

// <themeDir>/themes is where theme assets live
const themeDir = path.resolve(jlab.themeDir || outputDir);
// ensureAssets puts themes in the themes subdirectory
clean(path.join(themeDir, 'themes'));

// Configuration to handle extension assets
const extensionAssetConfig = Build.ensureAssets({
  packageNames: extensionPackages,
  output: buildDir,
  schemaOutput: schemaDir,
  themeOutput: themeDir
});

// Create the entry point and other assets in build directory.
const source = fs.readFileSync('index.template.js').toString();
const template = Handlebars.compile(source);
const extData = {
  jupyterlab_extensions: extensions,
  jupyterlab_mime_extensions: mimeExtensions
};

fs.writeFileSync(path.join(buildDir, 'index.js'), template(extData));

// Create the bootstrap file that loads federated extensions and calls the
// initialization logic in index.js
const entryPoint = path.join(buildDir, 'bootstrap.js');
fs.copySync('./bootstrap.js', entryPoint);

function createShared(packageData) {
  // Set up module federation sharing config
  const shared = {};
  const extensionPackages = packageData.jupyterlab.extensions;

  // Make sure any resolutions are shared
  for (let [pkg, requiredVersion] of Object.entries(packageData.resolutions)) {
    shared[pkg] = { requiredVersion };
  }

  // Add any extension packages that are not in resolutions (i.e., installed from npm)
  for (let pkg of extensionPackages) {
    if (!shared[pkg]) {
      shared[pkg] = {
        requiredVersion: require(`${pkg}/package.json`).version
      };
    }
  }

  // Add dependencies and sharedPackage config from extension packages if they
  // are not already in the shared config. This means that if there is a
  // conflict, the resolutions package version is the one that is shared.
  const extraShared = [];
  for (let pkg of extensionPackages) {
    let pkgShared = {};
    let {
      dependencies = {},
      jupyterlab: { sharedPackages = {} } = {}
    } = require(`${pkg}/package.json`);
    for (let [dep, requiredVersion] of Object.entries(dependencies)) {
      if (!shared[dep]) {
        pkgShared[dep] = { requiredVersion };
      }
    }

    // Overwrite automatic dependency sharing with custom sharing config
    for (let [dep, config] of Object.entries(sharedPackages)) {
      if (config === false) {
        delete pkgShared[dep];
      } else {
        if ('bundled' in config) {
          config.import = config.bundled;
          delete config.bundled;
        }
        pkgShared[dep] = config;
      }
    }
    extraShared.push(pkgShared);
  }

  // Now merge the extra shared config
  const mergedShare = {};
  for (let sharedConfig of extraShared) {
    for (let [pkg, config] of Object.entries(sharedConfig)) {
      // Do not override the basic share config from resolutions
      if (shared[pkg]) {
        continue;
      }

      // Add if we haven't seen the config before
      if (!mergedShare[pkg]) {
        mergedShare[pkg] = config;
        continue;
      }

      // Choose between the existing config and this new config. We do not try
      // to merge configs, which may yield a config no one wants
      let oldConfig = mergedShare[pkg];

      // if the old one has import: false, use the new one
      if (oldConfig.import === false) {
        mergedShare[pkg] = config;
      }
    }
  }

  Object.assign(shared, mergedShare);

  // Transform any file:// requiredVersion to the version number from the
  // imported package. This assumes (for simplicity) that the version we get
  // importing was installed from the file.
  for (let [pkg, { requiredVersion }] of Object.entries(shared)) {
    if (requiredVersion && requiredVersion.startsWith('file:')) {
      shared[pkg].requiredVersion = require(`${pkg}/package.json`).version;
    }
  }

  // Add singleton package information
  for (let pkg of packageData.jupyterlab.singletonPackages) {
    shared[pkg].singleton = true;
  }

  return shared;
}

const plugins = [
  new ModuleFederationPlugin({
    library: {
      type: 'var',
      name: ['_JUPYTERLAB', 'CORE_LIBRARY_FEDERATION']
    },
    name: 'CORE_FEDERATION',
    shared: createShared(packageData)
  })
];

module.exports = [
  merge(baseConfig, {
    mode: 'development',
    devtool: 'source-map',
    entry: ['./publicpath.js', entryPoint],
    output: {
      path: path.resolve(outputDir),
      library: {
        type: 'var',
        name: ['_JUPYTERLAB', 'CORE_OUTPUT']
      },
      filename: 'bundle.js'
    },
    optimization: {
      splitChunks: {
        chunks: 'all',
        cacheGroups: {
          jlab_core: {
            test: /[\\/]node_modules[\\/]@(jupyterlab|lumino)[\\/]/,
            name: 'jlab_core'
          }
        }
      }
    },
    plugins
  })
].concat(extensionAssetConfig);

// For debugging, write the config out
const logPath = path.join(buildDir, 'build_log.json');
fs.writeFileSync(logPath, JSON.stringify(module.exports, null, '  '));
<|endoftext|>


<commit_before>// This file was generated by ./generate_commands.js on Mon Sep 16 2013 12:06:11 GMT-0300 (ART)
module.exports = [
	"APPEND",
	"AUTH",
	"BGREWRITEAOF",
	"BGSAVE",
	"BITCOUNT",
	"BITOP",
	"BLPOP",
	"BRPOP",
	"BRPOPLPUSH",
	"CLIENT KILL",
	"CLIENT LIST",
	"CLIENT GETNAME",
	"CLIENT SETNAME",
	"CONFIG GET",
	"CONFIG REWRITE",
	"CONFIG SET",
	"CONFIG RESETSTAT",
	"DBSIZE",
	"DEBUG OBJECT",
	"DEBUG SEGFAULT",
	"DECR",
	"DECRBY",
	"DEL",
	"DISCARD",
	"DUMP",
	"ECHO",
	"EVAL",
	"EVALSHA",
	"EXEC",
	"EXISTS",
	"EXPIRE",
	"EXPIREAT",
	"FLUSHALL",
	"FLUSHDB",
	"GET",
	"GETBIT",
	"GETRANGE",
	"GETSET",
	"HDEL",
	"HEXISTS",
	"HGET",
	"HGETALL",
	"HINCRBY",
	"HINCRBYFLOAT",
	"HKEYS",
	"HLEN",
	"HMGET",
	"HMSET",
	"HSET",
	"HSETNX",
	"HVALS",
	"INCR",
	"INCRBY",
	"INCRBYFLOAT",
	"INFO",
	"KEYS",
	"LASTSAVE",
	"LINDEX",
	"LINSERT",
	"LLEN",
	"LPOP",
	"LPUSH",
	"LPUSHX",
	"LRANGE",
	"LREM",
	"LSET",
	"LTRIM",
	"MGET",
	"MIGRATE",
	"MONITOR",
	"MOVE",
	"MSET",
	"MSETNX",
	"MULTI",
	"OBJECT",
	"PERSIST",
	"PEXPIRE",
	"PEXPIREAT",
	"PING",
	"PSETEX",
	"PSUBSCRIBE",
	"PUBSUB",
	"PTTL",
	"PUBLISH",
	"PUNSUBSCRIBE",
	"QUIT",
	"RANDOMKEY",
	"RENAME",
	"RENAMENX",
	"RESTORE",
	"RPOP",
	"RPOPLPUSH",
	"RPUSH",
	"RPUSHX",
	"SADD",
	"SAVE",
	"SCARD",
	"SCRIPT EXISTS",
	"SCRIPT FLUSH",
	"SCRIPT KILL",
	"SCRIPT LOAD",
	"SDIFF",
	"SDIFFSTORE",
	"SELECT",
	"SET",
	"SETBIT",
	"SETEX",
	"SETNX",
	"SETRANGE",
	"SHUTDOWN",
	"SINTER",
	"SINTERSTORE",
	"SISMEMBER",
	"SLAVEOF",
	"SLOWLOG",
	"SMEMBERS",
	"SMOVE",
	"SORT",
	"SPOP",
	"SRANDMEMBER",
	"SREM",
	"STRLEN",
	"SUBSCRIBE",
	"SUNION",
	"SUNIONSTORE",
	"SYNC",
	"TIME",
	"TTL",
	"TYPE",
	"UNSUBSCRIBE",
	"UNWATCH",
	"WATCH",
	"ZADD",
	"ZCARD",
	"ZCOUNT",
	"ZINCRBY",
	"ZINTERSTORE",
	"ZRANGE",
	"ZRANGEBYSCORE",
	"ZRANK",
	"ZREM",
	"ZREMRANGEBYRANK",
	"ZREMRANGEBYSCORE",
	"ZREVRANGE",
	"ZREVRANGEBYSCORE",
	"ZREVRANK",
	"ZSCORE",
	"ZUNIONSTORE"
];
<commit_msg>Generated new commands<commit_after>// This file was generated by ./generate_commands.js on Sat Jan 04 2014 12:35:56 GMT-0800 (PST)
module.exports = [
	"APPEND",
	"AUTH",
	"BGREWRITEAOF",
	"BGSAVE",
	"BITCOUNT",
	"BITOP",
	"BLPOP",
	"BRPOP",
	"BRPOPLPUSH",
	"CLIENT KILL",
	"CLIENT LIST",
	"CLIENT GETNAME",
	"CLIENT SETNAME",
	"CONFIG GET",
	"CONFIG REWRITE",
	"CONFIG SET",
	"CONFIG RESETSTAT",
	"DBSIZE",
	"DEBUG OBJECT",
	"DEBUG SEGFAULT",
	"DECR",
	"DECRBY",
	"DEL",
	"DISCARD",
	"DUMP",
	"ECHO",
	"EVAL",
	"EVALSHA",
	"EXEC",
	"EXISTS",
	"EXPIRE",
	"EXPIREAT",
	"FLUSHALL",
	"FLUSHDB",
	"GET",
	"GETBIT",
	"GETRANGE",
	"GETSET",
	"HDEL",
	"HEXISTS",
	"HGET",
	"HGETALL",
	"HINCRBY",
	"HINCRBYFLOAT",
	"HKEYS",
	"HLEN",
	"HMGET",
	"HMSET",
	"HSET",
	"HSETNX",
	"HVALS",
	"INCR",
	"INCRBY",
	"INCRBYFLOAT",
	"INFO",
	"KEYS",
	"LASTSAVE",
	"LINDEX",
	"LINSERT",
	"LLEN",
	"LPOP",
	"LPUSH",
	"LPUSHX",
	"LRANGE",
	"LREM",
	"LSET",
	"LTRIM",
	"MGET",
	"MIGRATE",
	"MONITOR",
	"MOVE",
	"MSET",
	"MSETNX",
	"MULTI",
	"OBJECT",
	"PERSIST",
	"PEXPIRE",
	"PEXPIREAT",
	"PING",
	"PSETEX",
	"PSUBSCRIBE",
	"PUBSUB",
	"PTTL",
	"PUBLISH",
	"PUNSUBSCRIBE",
	"QUIT",
	"RANDOMKEY",
	"RENAME",
	"RENAMENX",
	"RESTORE",
	"RPOP",
	"RPOPLPUSH",
	"RPUSH",
	"RPUSHX",
	"SADD",
	"SAVE",
	"SCARD",
	"SCRIPT EXISTS",
	"SCRIPT FLUSH",
	"SCRIPT KILL",
	"SCRIPT LOAD",
	"SDIFF",
	"SDIFFSTORE",
	"SELECT",
	"SET",
	"SETBIT",
	"SETEX",
	"SETNX",
	"SETRANGE",
	"SHUTDOWN",
	"SINTER",
	"SINTERSTORE",
	"SISMEMBER",
	"SLAVEOF",
	"SLOWLOG",
	"SMEMBERS",
	"SMOVE",
	"SORT",
	"SPOP",
	"SRANDMEMBER",
	"SREM",
	"STRLEN",
	"SUBSCRIBE",
	"SUNION",
	"SUNIONSTORE",
	"SYNC",
	"TIME",
	"TTL",
	"TYPE",
	"UNSUBSCRIBE",
	"UNWATCH",
	"WATCH",
	"ZADD",
	"ZCARD",
	"ZCOUNT",
	"ZINCRBY",
	"ZINTERSTORE",
	"ZRANGE",
	"ZRANGEBYSCORE",
	"ZRANK",
	"ZREM",
	"ZREMRANGEBYRANK",
	"ZREMRANGEBYSCORE",
	"ZREVRANGE",
	"ZREVRANGEBYSCORE",
	"ZREVRANK",
	"ZSCORE",
	"ZUNIONSTORE",
	"SCAN",
	"SSCAN",
	"HSCAN",
	"ZSCAN"
];
<|endoftext|>


<commit_before>
export const getBtnTextByType = (type) => {
  switch (type) {
    case 'text':
      return 'report.inputText';
    case 'radio':
      return 'report.inputRadio';
    case 'select':
      return 'report.inputSelect';
    default:
      return 'report.input';
  }
};

export const parseQuestion = ({ question, form }, deviceLang) => {
  const lang = form.languages.includes(deviceLang) ? deviceLang : form.defaultLanguage;
  let parsedQuestion = { ...question };
  const whitelist = ['defaultValue', 'label', 'values', 'name'];
  whitelist.forEach((key) => {
    if (typeof parsedQuestion[key] === 'object' && typeof parsedQuestion[key][lang] !== 'undefined') {
      parsedQuestion = { ...parsedQuestion, [key]: parsedQuestion[key][lang] };
    }
  });
  if (parsedQuestion.childQuestions) {
    parsedQuestion.childQuestions = parsedQuestion.childQuestions.map((child) => parseQuestion({ question: child, form }, deviceLang));
  }
  return parsedQuestion;
};

export const getAnswers = (forms, formName) => {
  if (!forms) return null;
  if (forms[formName] && forms[formName].values) return forms[formName].values;
  return {};
};

export const getTemplate = (reports, formName) => {
  const list = reports.list[formName];
  const status = templateId => (
    reports.templates[templateId] && reports.templates[templateId].status
  );
  const templateId = list && list.area.templateId && status(list.area.templateId) !== 'unpublished' ?
    list.area.templateId : 'default';
  return Object.assign({}, reports.templates[templateId]);
};

export const getNextStep = ({ currentQuestion, questions, answers }) => {
  let next = 1;
  if (currentQuestion < questions.length - 1) {
    for (let i = currentQuestion + 1, qLength = questions.length; i < qLength; i++) {
      const nextConditions = questions[i].conditions;
      const nextHasConditions = nextConditions && nextConditions.length > 0;
      if (!nextHasConditions || (answers[nextConditions[0].name] === nextConditions[0].value)) {
        break;
      }
      next += 1;
    }
    return currentQuestion + next;
  }
  return null;
};

export const getFormFields = (template, answers) => {
  const fields = [0];
  template.questions.forEach((question, index) => {
    const nextStep = getNextStep({ currentQuestion: index, questions: template.questions, answers });
    if (nextStep) fields.push(nextStep);
  });
  return fields.map(field => template.questions[field].name);
};

export const isQuestionAnswered = (question, answers) => {
  if (!question) return false;
  if (question.type !== 'blob') {
    return typeof answers[question.name] !== 'undefined';
  }
  return answers[question.name] && !!answers[question.name].length;
};

export default {
  getBtnTextByType,
  parseQuestion,
  getTemplate,
  getAnswers,
  getFormFields,
  getNextStep,
  isQuestionAnswered
};
<commit_msg>Fix empty language break<commit_after>
export const getBtnTextByType = (type) => {
  switch (type) {
    case 'text':
      return 'report.inputText';
    case 'radio':
      return 'report.inputRadio';
    case 'select':
      return 'report.inputSelect';
    default:
      return 'report.input';
  }
};

export const parseQuestion = ({ question, form }, deviceLang) => {
  const lang = form.languages.includes(deviceLang) ? deviceLang : form.defaultLanguage;
  let parsedQuestion = { ...question };
  const whitelist = ['defaultValue', 'label', 'values', 'name'];
  whitelist.forEach((key) => {
    if (typeof parsedQuestion[key] === 'object') {
      const parsedValue = typeof parsedQuestion[key][lang] !== 'undefined'
        ? parsedQuestion[key][lang]
        : '';
      parsedQuestion = { ...parsedQuestion, [key]: parsedValue };
    }
  });
  if (parsedQuestion.childQuestions) {
    parsedQuestion.childQuestions = parsedQuestion.childQuestions.map((child) => parseQuestion({ question: child, form }, deviceLang));
  }
  return parsedQuestion;
};

export const getAnswers = (forms, formName) => {
  if (!forms) return null;
  if (forms[formName] && forms[formName].values) return forms[formName].values;
  return {};
};

export const getTemplate = (reports, formName) => {
  const list = reports.list[formName];
  const status = templateId => (
    reports.templates[templateId] && reports.templates[templateId].status
  );
  const templateId = list && list.area.templateId && status(list.area.templateId) !== 'unpublished' ?
    list.area.templateId : 'default';
  return Object.assign({}, reports.templates[templateId]);
};

export const getNextStep = ({ currentQuestion, questions, answers }) => {
  let next = 1;
  if (currentQuestion < questions.length - 1) {
    for (let i = currentQuestion + 1, qLength = questions.length; i < qLength; i++) {
      const nextConditions = questions[i].conditions;
      const nextHasConditions = nextConditions && nextConditions.length > 0;
      if (!nextHasConditions || (answers[nextConditions[0].name] === nextConditions[0].value)) {
        break;
      }
      next += 1;
    }
    return currentQuestion + next;
  }
  return null;
};

export const getFormFields = (template, answers) => {
  const fields = [0];
  template.questions.forEach((question, index) => {
    const nextStep = getNextStep({ currentQuestion: index, questions: template.questions, answers });
    if (nextStep) fields.push(nextStep);
  });
  return fields.map(field => template.questions[field].name);
};

export const isQuestionAnswered = (question, answers) => {
  if (!question) return false;
  if (question.type !== 'blob') {
    return typeof answers[question.name] !== 'undefined';
  }
  return answers[question.name] && !!answers[question.name].length;
};

export default {
  getBtnTextByType,
  parseQuestion,
  getTemplate,
  getAnswers,
  getFormFields,
  getNextStep,
  isQuestionAnswered
};
<|endoftext|>


<commit_before>import React, { PropTypes, Component } from 'react';

export default class HomePage extends Component {
   render() {
    return(

A Warm Welcome!

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsa, ipsam, eligendi, in quo sunt possimus non incidunt odit vero aliquid similique quaerat nam nobis illo aspernatur vitae fugiat numquam repellat.

Call to action!

Latest Features

Feature Label

Lorem ipsum dolor sit amet, consectetur adipisicing elit.

                                Buy Now! More Info

Feature Label

Lorem ipsum dolor sit amet, consectetur adipisicing elit.

                                Buy Now! More Info

Feature Label

Lorem ipsum dolor sit amet, consectetur adipisicing elit.

                                Buy Now! More Info

Feature Label

Lorem ipsum dolor sit amet, consectetur adipisicing elit.

                                Buy Now! More Info

      );
    }
  };
<commit_msg>Merging<commit_after>import React, { PropTypes, Component } from 'react';

export default class HomePage extends Component {
   render() {
    return(

Hey there!

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsa, ipsam, eligendi, in quo sunt possimus non incidunt odit vero aliquid similique quaerat nam nobis illo aspernatur vitae fugiat numquam repellat.

Call to action!

Latest Features

Feature Label

Lorem ipsum dolor sit amet, consectetur adipisicing elit.

                                Buy Now! More Info

Feature Label

Lorem ipsum dolor sit amet, consectetur adipisicing elit.

                                Buy Now! More Info

Feature Label

Lorem ipsum dolor sit amet, consectetur adipisicing elit.

                                Buy Now! More Info

Feature Label

Lorem ipsum dolor sit amet, consectetur adipisicing elit.

                                Buy Now! More Info

      );
    }
  };
<|endoftext|>


<commit_before>/**
  @module ember-flexberry-gis
*/

import Ember from 'ember';
import BaseLayer from '../base-layer';

/**
  WFS layer component for leaflet map.

  @class WfsLayerComponent
  @extend BaseLayerComponent
 */
export default BaseLayer.extend({
  leafletOptions: [
    'url',
    'version',
    'namespaceUri',
    'typeNS',
    'typeName',
    'typeNSName',
    'geometryField',
    'crs',
    'maxFeatures',
    'showExisting',
    'style'
  ],

  /**
    Features read format.
    Server responses format will rely on it.

    @property featuresReadFormat
    @type {Object}
  */
  featuresReadFormat: Ember.computed('format', 'options.crs', 'options.geometryField', function () {
    let format = this.get('format');
    let availableFormats = Ember.A(Object.keys(L.Format) || []).filter((format) => {
      format = format.toLowerCase();
      return format !== 'base' && format !== 'scheme';
    });
    availableFormats = Ember.A(availableFormats);
    Ember.assert(
      `Wrong value of \`format\` property: ${format}. ` +
      `Allowed values are: [\`${availableFormats.join(`\`, \``)}\`].`,
      availableFormats.contains(format));

    let options = this.get('options');
    let crs = Ember.get(options, 'crs');
    let geometryField = Ember.get(options, 'geometryField');
    return new L.Format[format]({
      crs,
      geometryField
    });
  }),

  /**
    Performs 'getFeature' request to WFS-service related to layer.

    @param {L.WFS initialization options} options
    Options of WFS plugin layer
    @param bool single
    Result should be single layer
  */
  _getFeature(options, single = false) {
    return new Ember.RSVP.Promise((resolve, reject) => {
      let layer = null;
      let destroyLayer = () => {
        if (Ember.isNone(layer)) {
          return;
        }

        layer.off('load', onLayerLoad);
        layer.off('error', onLayerError);
        layer = null;
      };

      let onLayerLoad = (e) => {

        if (single) {
          resolve(e.target);
        } else {
          let features = Ember.A();

          // Instead of injectLeafletLayersIntoGeoJSON to avoid duplicate repropjection,
          // retrieve features from already projected layers & inject layers into retrieved features.
          e.target.eachLayer((layer) => {
            let feature = layer.feature;
            feature.leafletLayer = layer;
            features.pushObject(feature);
          });

          resolve(features);
        }

        destroyLayer();
      };

      let onLayerError = (e) => {
        reject(e.error || e);

        destroyLayer();
      };

      options = Ember.$.extend(options || {}, {
        showExisting: true
      });

      layer = this.createLayer(options)
        .once('load', onLayerLoad)
        .once('error', onLayerError);
    });
  },

  /**
    Sets leaflet layer's visibility.

    @method _setLayerOpacity
    @private
  */
  _setLayerOpacity() {
    let leafletLayer = this.get('_leafletObject');
    let leafletLayerStyle = Ember.get(leafletLayer, 'options.style');
    if (Ember.isNone(leafletLayerStyle)) {
      leafletLayerStyle = {};
      Ember.set(leafletLayer, 'options.style', leafletLayerStyle);
    }

    let opacity = this.get('opacity');
    Ember.set(leafletLayerStyle, 'opacity', opacity);
    Ember.set(leafletLayerStyle, 'fillOpacity', opacity);

    leafletLayer.setStyle(leafletLayerStyle);
  },

  /**
    Creates leaflet layer related to layer type.

    @method createLayer
    @returns L.Layer|Ember.RSVP.Promise
    Leaflet layer or promise returning such layer.
  */
  createLayer(options) {
    options = Ember.$.extend(true, {}, this.get('options'), options);
    let featuresReadFormat = this.get('featuresReadFormat');

    return L.wfs(options, featuresReadFormat);
  },

  /**
    Handles 'flexberry-map:identify' event of leaflet map.

    @method identify
    @param {Object} e Event object.
    @param {L.Polygon} polygonLayer Polygon layer related to given area.
    @param {Object[]} layers Objects describing those layers which must be identified.
    @param {Object[]} results Objects describing identification results.
    Every result-object has the following structure: { layer: ..., features: [...] },
    where 'layer' is metadata of layer related to identification result, features is array
    containing (GeoJSON feature-objects)[http://geojson.org/geojson-spec.html#feature-objects]
    or a promise returning such array.
  */
  identify(e) {
    let filter = new L.Filter.Intersects().append(e.polygonLayer, this.get('geometryField'), this.get('crs'));

    let featuresPromise = this._getFeature({
      filter
    });

    return featuresPromise;
  },

  /**
    Handles 'flexberry-map:search' event of leaflet map.

    @method search
    @param {Object} e Event object.
    @param {L.LatLng} e.latlng Center of the search area.
    @param {Object[]} layer Object describing layer that must be searched.
    @param {Object} searchOptions Search options related to layer type.
    @param {Object} results Hash containing search results.
    @param {Object[]} results.features Array containing (GeoJSON feature-objects)[http://geojson.org/geojson-spec.html#feature-objects]
    or a promise returning such array.
  */
  search(e) {
    let propertyName = e.searchOptions.propertyName;

    if (Ember.isNone(propertyName)) {
      return;
    }

    let filter = new L.Filter.Like().append(propertyName, '*' + e.searchOptions.queryString + '*', {
      matchCase: false
    });

    let featuresPromise = this._getFeature({
      filter,
      maxFeatures: e.searchOptions.maxResultsCount,
      style: {
        color: 'yellow'
      }
    });

    return featuresPromise;
  },

  /**
    Handles 'flexberry-map:query' event of leaflet map.

    @method _query
    @param {Object[]} layerLinks Array containing metadata for query
    @param {Object} e Event object.
    @param {Object} queryFilter Object with query filter paramteres
    @param {Object[]} results.features Array containing leaflet layers objects
    or a promise returning such array.
  */
  query(layerLinks, e) {
    let filter = new L.Filter.EQ();
    let queryFilter = e.queryFilter;

    layerLinks.forEach((link) => {
      let linkParameters = link.get('linkParameter');

      if (Ember.isArray(linkParameters) && linkParameters.length > 0) {
        linkParameters.forEach(linkParam => {
          let property = linkParam.get('layerField');
          let propertyValue = queryFilter[linkParam.get('queryKey')];

          filter.append(property, propertyValue);
        });
      }
    });

    let featuresPromise = this._getFeature({
      filter
    });

    return featuresPromise;
  }
});
<commit_msg>Refactored according to #55 in Leaflet-WFST (wfs layer opacity)<commit_after>/**
  @module ember-flexberry-gis
*/

import Ember from 'ember';
import BaseLayer from '../base-layer';

/**
  WFS layer component for leaflet map.

  @class WfsLayerComponent
  @extend BaseLayerComponent
 */
export default BaseLayer.extend({
  leafletOptions: [
    'url',
    'version',
    'namespaceUri',
    'typeNS',
    'typeName',
    'typeNSName',
    'geometryField',
    'crs',
    'maxFeatures',
    'showExisting',
    'style'
  ],

  /**
    Features read format.
    Server responses format will rely on it.

    @property featuresReadFormat
    @type {Object}
  */
  featuresReadFormat: Ember.computed('format', 'options.crs', 'options.geometryField', function () {
    let format = this.get('format');
    let availableFormats = Ember.A(Object.keys(L.Format) || []).filter((format) => {
      format = format.toLowerCase();
      return format !== 'base' && format !== 'scheme';
    });
    availableFormats = Ember.A(availableFormats);
    Ember.assert(
      `Wrong value of \`format\` property: ${format}. ` +
      `Allowed values are: [\`${availableFormats.join(`\`, \``)}\`].`,
      availableFormats.contains(format));

    let options = this.get('options');
    let crs = Ember.get(options, 'crs');
    let geometryField = Ember.get(options, 'geometryField');
    return new L.Format[format]({
      crs,
      geometryField
    });
  }),

  /**
    Performs 'getFeature' request to WFS-service related to layer.

    @param {L.WFS initialization options} options
    Options of WFS plugin layer
    @param bool single
    Result should be single layer
  */
  _getFeature(options, single = false) {
    return new Ember.RSVP.Promise((resolve, reject) => {
      let layer = null;
      let destroyLayer = () => {
        if (Ember.isNone(layer)) {
          return;
        }

        layer.off('load', onLayerLoad);
        layer.off('error', onLayerError);
        layer = null;
      };

      let onLayerLoad = (e) => {

        if (single) {
          resolve(e.target);
        } else {
          let features = Ember.A();

          // Instead of injectLeafletLayersIntoGeoJSON to avoid duplicate repropjection,
          // retrieve features from already projected layers & inject layers into retrieved features.
          e.target.eachLayer((layer) => {
            let feature = layer.feature;
            feature.leafletLayer = layer;
            features.pushObject(feature);
          });

          resolve(features);
        }

        destroyLayer();
      };

      let onLayerError = (e) => {
        reject(e.error || e);

        destroyLayer();
      };

      options = Ember.$.extend(options || {}, {
        showExisting: true
      });

      layer = this.createLayer(options)
        .once('load', onLayerLoad)
        .once('error', onLayerError);
    });
  },

  /**
    Creates leaflet layer related to layer type.

    @method createLayer
    @returns L.Layer|Ember.RSVP.Promise
    Leaflet layer or promise returning such layer.
  */
  createLayer(options) {
    options = Ember.$.extend(true, {}, this.get('options'), options);
    let featuresReadFormat = this.get('featuresReadFormat');

    return L.wfs(options, featuresReadFormat);
  },

  /**
    Handles 'flexberry-map:identify' event of leaflet map.

    @method identify
    @param {Object} e Event object.
    @param {L.Polygon} polygonLayer Polygon layer related to given area.
    @param {Object[]} layers Objects describing those layers which must be identified.
    @param {Object[]} results Objects describing identification results.
    Every result-object has the following structure: { layer: ..., features: [...] },
    where 'layer' is metadata of layer related to identification result, features is array
    containing (GeoJSON feature-objects)[http://geojson.org/geojson-spec.html#feature-objects]
    or a promise returning such array.
  */
  identify(e) {
    let filter = new L.Filter.Intersects().append(e.polygonLayer, this.get('geometryField'), this.get('crs'));

    let featuresPromise = this._getFeature({
      filter
    });

    return featuresPromise;
  },

  /**
    Handles 'flexberry-map:search' event of leaflet map.

    @method search
    @param {Object} e Event object.
    @param {L.LatLng} e.latlng Center of the search area.
    @param {Object[]} layer Object describing layer that must be searched.
    @param {Object} searchOptions Search options related to layer type.
    @param {Object} results Hash containing search results.
    @param {Object[]} results.features Array containing (GeoJSON feature-objects)[http://geojson.org/geojson-spec.html#feature-objects]
    or a promise returning such array.
  */
  search(e) {
    let propertyName = e.searchOptions.propertyName;

    if (Ember.isNone(propertyName)) {
      return;
    }

    let filter = new L.Filter.Like().append(propertyName, '*' + e.searchOptions.queryString + '*', {
      matchCase: false
    });

    let featuresPromise = this._getFeature({
      filter,
      maxFeatures: e.searchOptions.maxResultsCount,
      style: {
        color: 'yellow'
      }
    });

    return featuresPromise;
  },

  /**
    Handles 'flexberry-map:query' event of leaflet map.

    @method _query
    @param {Object[]} layerLinks Array containing metadata for query
    @param {Object} e Event object.
    @param {Object} queryFilter Object with query filter paramteres
    @param {Object[]} results.features Array containing leaflet layers objects
    or a promise returning such array.
  */
  query(layerLinks, e) {
    let filter = new L.Filter.EQ();
    let queryFilter = e.queryFilter;

    layerLinks.forEach((link) => {
      let linkParameters = link.get('linkParameter');

      if (Ember.isArray(linkParameters) && linkParameters.length > 0) {
        linkParameters.forEach(linkParam => {
          let property = linkParam.get('layerField');
          let propertyValue = queryFilter[linkParam.get('queryKey')];

          filter.append(property, propertyValue);
        });
      }
    });

    let featuresPromise = this._getFeature({
      filter
    });

    return featuresPromise;
  }
});
<|endoftext|>


<commit_before>//= require support/third_party_for_specs
//= require support/prop_types
//= require support/test_utils
//= require support/mock_react_router
//= require support/magic_lamp
//= require_self
//= require support/utils
/* global window*/

App = {};

expect = window.chai.expect;

(function () {
  'use strict';

  MagicLamp.preload();

  beforeEach(function () {
    this.sandbox = sinon.sandbox.create();
    this.sandbox.stub(window.console, 'warn', function (message) {
      throw message;
    });
  });

  afterEach(function () {
    MagicLamp.clean();
    this.sandbox.restore();
  });
})();
<commit_msg>Switch order<commit_after>//= require support/third_party_for_specs
//= require support/prop_types
//= require support/test_utils
//= require support/mock_react_router
//= require support/magic_lamp
//= require_self
//= require support/utils
/* global window*/

App = {};

expect = window.chai.expect;

(function () {
  'use strict';

  MagicLamp.preload();

  beforeEach(function () {
    this.sandbox = sinon.sandbox.create();
    this.sandbox.stub(window.console, 'warn', function (message) {
      throw message;
    });
  });

  afterEach(function () {
    this.sandbox.restore();
    MagicLamp.clean();
  });
})();
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { Container, ContainerGroup, HistoryMatch } from '../../../../dist/tab-history-library'
import WindowMaster1 from '../components/WindowMaster1'
import WindowMaster2 from '../components/WindowMaster2'
import WindowPage from '../components/WindowPage'
import './Windows.css'

function getWindowZIndex(indexedStackOrder, index) {
  if (indexedStackOrder.length > index) {
    return indexedStackOrder.length - indexedStackOrder[index] + 1
  }
  else {
    return 1
  }
}

const Window = ({className, initialUrl, masterComponent, index, indexedStackOrder, switchTo}) => (
  <Container initialUrl={initialUrl} patterns={[initialUrl, initialUrl + '/:page']}>
    <div className={`window ${className}`} onClick={() => switchTo(index)}
         style={{zIndex: getWindowZIndex(indexedStackOrder, index)}}>
      <HistoryMatch exactly pattern={initialUrl} component={masterComponent}/>
      <HistoryMatch exactly pattern={initialUrl + '/:page'} component={WindowPage}/>

  </Container>
)

export default class Windows extends Component {
  constructor(props) {
    super(props)
    this.state = {
      activeWindowIndex: 0,
      indexedStackOrder: []
    }
  }

  onContainerSwitch(state) {
    this.setState({
      indexedStackOrder: state.indexedStackOrder
    })
  }

  renderWindow(index, masterComponent) {
    return (<Window className={'window' + (index + 1)}
                    initialUrl={'/windows/' + (index + 1)}
                    index={index}
                    masterComponent={masterComponent}
                    indexedStackOrder={this.state.indexedStackOrder}
                    switchTo={() => this.setState({activeWindowIndex: index})} />)
  }

  render() {
    return (

Windows example

Each window has its own individual history.

Clicking on a window brings it to the front.

      <ContainerGroup currentContainerIndex={this.state.activeWindowIndex}
                      onContainerSwitch={this.onContainerSwitch.bind(this)}
                      useDefaultContainer={false}>
        {this.renderWindow(0, WindowMaster1)}
        {this.renderWindow(1, WindowMaster2)}
      </ContainerGroup>

)
  }
}<commit_msg>Fixed bug but can't test because of async-ness in redux-persist<commit_after>import React, { Component } from 'react'
import { Container, ContainerGroup, HistoryMatch } from '../../../../dist/tab-history-library'
import WindowMaster1 from '../components/WindowMaster1'
import WindowMaster2 from '../components/WindowMaster2'
import WindowPage from '../components/WindowPage'
import './Windows.css'

function getWindowZIndex(indexedStackOrder, index) {
  if (indexedStackOrder.length > index) {
    return indexedStackOrder.length - indexedStackOrder[index] + 1
  }
  else {
    return 1
  }
}

const Window = ({className, initialUrl, masterComponent, index, indexedStackOrder, switchTo}) => (
  <Container initialUrl={initialUrl} patterns={[initialUrl, initialUrl + '/:page']}>
    <div className={`window ${className}`} onClick={() => switchTo(index)}
         style={{zIndex: getWindowZIndex(indexedStackOrder, index)}}>
      <HistoryMatch exactly pattern={initialUrl} component={masterComponent}/>
      <HistoryMatch exactly pattern={initialUrl + '/:page'} component={WindowPage}/>

  </Container>
)

export default class Windows extends Component {
  constructor(props) {
    super(props)
    this.state = {
      activeWindowIndex: 0,
      indexedStackOrder: []
    }
  }

  onContainerSwitch({activeContainer, indexedStackOrder}) {
    this.setState({
      activeWindowIndex: activeContainer.index,
      indexedStackOrder
    })
  }

  renderWindow(index, masterComponent) {
    return (<Window className={'window' + (index + 1)}
                    initialUrl={'/windows/' + (index + 1)}
                    index={index}
                    masterComponent={masterComponent}
                    indexedStackOrder={this.state.indexedStackOrder}
                    switchTo={() => this.setState({activeWindowIndex: index})} />)
  }

  render() {
    return (

Windows example

Each window has its own individual history.

Clicking on a window brings it to the front.

      <ContainerGroup currentContainerIndex={this.state.activeWindowIndex}
                      onContainerSwitch={this.onContainerSwitch.bind(this)}
                      useDefaultContainer={false}>
        {this.renderWindow(0, WindowMaster1)}
        {this.renderWindow(1, WindowMaster2)}
      </ContainerGroup>

)
  }
}<|endoftext|>


<commit_before>(function() {
    'use strict';

    var directives = angular.module('redash.directives', []);

    directives.directive('rdTab', ['$location', function($location) {
        return {
            restrict: 'E',
            scope: {
                'id': '@',
                'name': '@'
            },
            transclude: true,
            template: '
{{name}}
',
            replace: true,
            link: function(scope) {
                scope.$watch(function(){return scope.$parent.selectedTab}, function(tab) {
                    scope.selectedTab = tab;
                });
            }
        }
    }]);

    directives.directive('rdTabs', ['$location', '$rootScope', function($location, $rootScope) {
        return {
            restrict: 'E',
            scope: {
                tabsCollection: '=',
                selectedTab: '='
            },
            template: '

{{tab.name}}

',
            replace: true,
            link: function($scope, element, attrs) {
                $scope.selectTab = function(tabKey) {
                    $scope.selectedTab  = _.find($scope.tabsCollection, function(tab) { return tab.key == tabKey; });
                }

                $scope.$watch(function() { return $location.hash()}, function(hash) {
                    if (hash) {
                        $scope.selectTab($location.hash());
                    } else {
                        $scope.selectTab($scope.tabsCollection[0].key);
                    }
                });
            }
        }
    }]);

    directives.directive('editVisulatizationForm', ['Visualization', 'growl', function(Visualization, growl) {
        return {
            restrict: 'E',
            templateUrl: '/views/edit_visualization.html',
            replace: true,
            scope: {
                query: '=',
                vis: '=?'
            },
            link: function(scope, element, attrs) {
                scope.advancedMode = false;
                scope.visTypes = {
                    'Chart': Visualization.prototype.TYPES.CHART,
                    'Cohort': Visualization.prototype.TYPES.COHORT
                };
                scope.seriesTypes = {
                    'Line': Visualization.prototype.SERIES_TYPES.LINE,
                    'Bar': Visualization.prototype.SERIES_TYPES.BAR,
                    'Area': Visualization.prototype.SERIES_TYPES.AREA
                };

                if (!scope.vis) {
                    // create new visualization
                    // wait for query to load to populate with defaults
                    var unwatch = scope.$watch('query', function(q) {
                        if (q && q.id) {
                            unwatch();
                            scope.vis = {
                                'query_id': q.id,
                                'type': Visualization.prototype.TYPES.CHART,
                                'name': '',
                                'description': q.description,
                                'options': newOptions()
                            };
                        }
                    }, true);
                }

                function newOptions(chartType) {
                    if (chartType === Visualization.prototype.TYPES.COHORT) {
                        // empty config at the moment
                        return {};
                    }

                    // Chart
                    return {
                        'series': {
                            'type': Visualization.prototype.SERIES_TYPES.LINE
                        }
                    };
                }

                scope.$watch('vis.type', function(type) {
                    // if not edited by user, set name to match type
                    if (type && scope.vis && !scope.visForm.name.$dirty) {
                        // poor man's titlecase
                        scope.vis.name = scope.vis.type[0] + scope.vis.type.slice(1).toLowerCase();
                    }
                });

                scope.toggleAdvancedMode = function() {
                    scope.advancedMode = !scope.advancedMode;
                };

                scope.typeChanged = function() {
                    scope.vis.options = newOptions();
                };

                scope.submit = function() {
                    Visualization.save(scope.vis, function success(result) {
                        growl.addSuccessMessage("Visualization saved");

                        scope.vis = result;

                        var visIds = _.pluck(scope.query.visualizations, 'id');
                        var index = visIds.indexOf(result.id);
                        if (index > -1) {
                            scope.query.visualizations[index] = result;
                        } else {
                            scope.query.visualizations.push(result);
                        }
                    }, function error() {
                        growl.addErrorMessage("Visualization could not be saved");
                    });
                };
            }
        }
    }]);

    directives.directive('editDashboardForm', ['$http', '$location', '$timeout', 'Dashboard', function($http, $location, $timeout, Dashboard) {
        return {
            restrict: 'E',
            scope: {
                dashboard: '='
            },
            templateUrl: '/views/edit_dashboard.html',
            replace: true,
            link: function($scope, element, attrs) {
                var gridster = element.find(".gridster ul").gridster({
                    widget_margins: [5, 5],
                    widget_base_dimensions: [260, 100],
                    min_cols: 2,
                    max_cols: 2,
                    serialize_params: function($w, wgd) {
                        return {
                            col: wgd.col,
                            row: wgd.row,
                            id: $w.data('widget-id')
                        }
                    }
                }).data('gridster');

                var gsItemTemplate = '
' +
                                 '
{name}' +
                                 '

';

                $scope.$watch('dashboard.widgets', function(widgets) {
                    $timeout(function () {
                        gridster.remove_all_widgets();

                        if (widgets && widgets.length) {
                            var layout = [];

                            _.each(widgets, function(row, rowIndex) {
                                _.each(row, function(widget, colIndex) {
                                    layout.push({
                                        id: widget.id,
                                        col: colIndex+1,
                                        row: rowIndex+1,
                                        ySize: 1,
                                        xSize: widget.width,
                                        name: widget.visualization.query.name
                                    });
                                });
                            });

                            _.each(layout, function(item) {
                                var el = gsItemTemplate.replace('{id}', item.id).replace('{name}', item.name);
                                gridster.add_widget(el, item.xSize, item.ySize, item.col, item.row);

                            });
                        }
                    });
                }, true);

                $scope.saveDashboard = function() {
                    $scope.saveInProgress = true;
                    // TODO: we should use the dashboard service here.
                    if ($scope.dashboard.id) {
                        var positions = $(element).find('.gridster ul').data('gridster').serialize();
                        var layout = [];
                        _.each(_.sortBy(positions, function (pos) {
                            return pos.row * 10 + pos.col;
                        }), function (pos) {
                            var row = pos.row - 1;
                            var col = pos.col - 1;
                            layout[row] = layout[row] || [];
                            if (col > 0 && layout[row][col - 1] == undefined) {
                                layout[row][col - 1] = pos.id;
                            } else {
                                layout[row][col] = pos.id;
                            }

                        });
                        $scope.dashboard.layout = layout;

                        layout = JSON.stringify(layout);
                        $http.post('/api/dashboards/' + $scope.dashboard.id, {'name': $scope.dashboard.name, 'layout': layout}).success(function(response) {
                            $scope.dashboard = new Dashboard(response);
                            $scope.saveInProgress = false;
                            $(element).modal('hide');
                        })
                    } else {
                        $http.post('/api/dashboards', {'name': $scope.dashboard.name}).success(function(response) {
                            $(element).modal('hide');
                            $location.path('/dashboard/' + response.slug).replace();
                        })
                    }
                }

            }
        }
    }]);

    directives.directive('newWidgetForm', ['$http', 'Query', function($http, Query) {
        return {
            restrict: 'E',
            scope: {
                dashboard: '='
            },
            templateUrl: '/views/new_widget_form.html',
            replace: true,
            link: function($scope, element, attrs) {
                $scope.widgetSizes = [{name: 'Regular', value: 1}, {name: 'Double', value: 2}];

                var reset = function() {
                    $scope.saveInProgress = false;
                    $scope.widgetSize = 1;
                    $scope.queryId = null;
                    $scope.selectedVis = null;

                }

                reset();

                $scope.loadVisualizations = function() {
                    if (!$scope.queryId) {
                        return;
                    }

                    Query.get({
                        id: $scope.queryId
                    }, function(query) {
                        if (query) {
                            $scope.query = query;
                            if(query.visualizations.length) {
                                $scope.selectedVis = query.visualizations[0];
                            }
                        }
                    });
                };

                $scope.saveWidget = function() {
                    $scope.saveInProgress = true;

                    var widget = {
                        'visualization_id': $scope.selectedVis.id,
                        'dashboard_id': $scope.dashboard.id,
                        'options': {},
                        'width': $scope.widgetSize
                    }

                    $http.post('/api/widgets', widget).success(function(response) {
                        // update dashboard layout
                        $scope.dashboard.layout = response['layout'];
                        if (response['new_row']) {
                            $scope.dashboard.widgets.push([response['widget']]);
                        } else {
                            $scope.dashboard.widgets[$scope.dashboard.widgets.length-1].push(response['widget']);
                        }

                        // close the dialog
                        $('#add_query_dialog').modal('hide');
                        reset();
                    })
                }

            }
        }
    }])

    // From: http://jsfiddle.net/joshdmiller/NDFHg/
    directives.directive('editInPlace', function () {
        return {
            restrict: 'E',
            scope: {
                value: '=',
                ignoreBlanks: '=',
                editable: '='
            },
            template: function(tElement, tAttrs) {
                var elType = tAttrs.editor || 'input';
                var placeholder = tAttrs.placeholder || 'Click to edit';
                return '' +
                       '' + placeholder + '' +
                       '<{elType} ng-model="value" class="form-control" rows="2"></{elType}>'.replace('{elType}', elType);
            },
            link: function ($scope, element, attrs) {
                // Let's get a reference to the input element, as we'll want to reference it.
                var inputElement = angular.element(element.children()[2]);

                // This directive should have a set class so we can style it.
                element.addClass('edit-in-place');

                // Initially, we're not editing.
                $scope.editing = false;

                // ng-click handler to activate edit-in-place
                $scope.edit = function () {
                    if ($scope.ignoreBlanks) {
                        $scope.oldValue = $scope.value;
                    }

                    $scope.editing = true;

                    // We control display through a class on the directive itself. See the CSS.
                    element.addClass('active');

                    // And we must focus the element.
                    // `angular.element()` provides a chainable array, like jQuery so to access a native DOM function,
                    // we have to reference the first element in the array.
                    inputElement[0].focus();
                };

                $(inputElement).blur(function() {
                    if ($scope.ignoreBlanks && _.isEmpty($scope.value)) {
                        $scope.value = $scope.oldValue;
                    }
                    $scope.editing = false;
                    element.removeClass('active');
                })
            }
        };
    });

    // http://stackoverflow.com/a/17904092/1559840
    directives.directive('jsonText', function() {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function(scope, element, attr, ngModel) {
              function into(input) {
                return JSON.parse(input);
              }
              function out(data) {
                return JSON.stringify(data, undefined, 2);
              }
              ngModel.$parsers.push(into);
              ngModel.$formatters.push(out);

            }
        };
    });

    directives.directive('rdTimer', ['$timeout', function ($timeout) {
        return {
            restrict: 'E',
            scope: { timestamp: '=' },
            template: '{{currentTime}}',
            controller: ['$scope' ,function ($scope) {
                $scope.currentTime = "00:00:00";
                var currentTimeout = null;

                var updateTime = function() {
                    $scope.currentTime = moment(moment() - moment($scope.timestamp)).utc().format("HH:mm:ss")
                    currentTimeout = $timeout(updateTime, 1000);
                }

                var cancelTimer = function() {
                    if (currentTimeout) {
                        $timeout.cancel(currentTimeout);
                        currentTimeout = null;
                    }
                }

                updateTime();

                $scope.$on('$destroy', function () {
                    cancelTimer();
                });
            }]
        };
    }]);
})();
<commit_msg>Set default visualization description to ''.<commit_after>(function() {
    'use strict';

    var directives = angular.module('redash.directives', []);

    directives.directive('rdTab', ['$location', function($location) {
        return {
            restrict: 'E',
            scope: {
                'id': '@',
                'name': '@'
            },
            transclude: true,
            template: '
{{name}}
',
            replace: true,
            link: function(scope) {
                scope.$watch(function(){return scope.$parent.selectedTab}, function(tab) {
                    scope.selectedTab = tab;
                });
            }
        }
    }]);

    directives.directive('rdTabs', ['$location', '$rootScope', function($location, $rootScope) {
        return {
            restrict: 'E',
            scope: {
                tabsCollection: '=',
                selectedTab: '='
            },
            template: '

{{tab.name}}

',
            replace: true,
            link: function($scope, element, attrs) {
                $scope.selectTab = function(tabKey) {
                    $scope.selectedTab  = _.find($scope.tabsCollection, function(tab) { return tab.key == tabKey; });
                }

                $scope.$watch(function() { return $location.hash()}, function(hash) {
                    if (hash) {
                        $scope.selectTab($location.hash());
                    } else {
                        $scope.selectTab($scope.tabsCollection[0].key);
                    }
                });
            }
        }
    }]);

    directives.directive('editVisulatizationForm', ['Visualization', 'growl', function(Visualization, growl) {
        return {
            restrict: 'E',
            templateUrl: '/views/edit_visualization.html',
            replace: true,
            scope: {
                query: '=',
                vis: '=?'
            },
            link: function(scope, element, attrs) {
                scope.advancedMode = false;
                scope.visTypes = {
                    'Chart': Visualization.prototype.TYPES.CHART,
                    'Cohort': Visualization.prototype.TYPES.COHORT
                };
                scope.seriesTypes = {
                    'Line': Visualization.prototype.SERIES_TYPES.LINE,
                    'Bar': Visualization.prototype.SERIES_TYPES.BAR,
                    'Area': Visualization.prototype.SERIES_TYPES.AREA
                };

                if (!scope.vis) {
                    // create new visualization
                    // wait for query to load to populate with defaults
                    var unwatch = scope.$watch('query', function(q) {
                        if (q && q.id) {
                            unwatch();
                            scope.vis = {
                                'query_id': q.id,
                                'type': Visualization.prototype.TYPES.CHART,
                                'name': '',
                                'description': q.description || '',
                                'options': newOptions()
                            };
                        }
                    }, true);
                }

                function newOptions(chartType) {
                    if (chartType === Visualization.prototype.TYPES.COHORT) {
                        // empty config at the moment
                        return {};
                    }

                    // Chart
                    return {
                        'series': {
                            'type': Visualization.prototype.SERIES_TYPES.LINE
                        }
                    };
                }

                scope.$watch('vis.type', function(type) {
                    // if not edited by user, set name to match type
                    if (type && scope.vis && !scope.visForm.name.$dirty) {
                        // poor man's titlecase
                        scope.vis.name = scope.vis.type[0] + scope.vis.type.slice(1).toLowerCase();
                    }
                });

                scope.toggleAdvancedMode = function() {
                    scope.advancedMode = !scope.advancedMode;
                };

                scope.typeChanged = function() {
                    scope.vis.options = newOptions();
                };

                scope.submit = function() {
                    Visualization.save(scope.vis, function success(result) {
                        growl.addSuccessMessage("Visualization saved");

                        scope.vis = result;

                        var visIds = _.pluck(scope.query.visualizations, 'id');
                        var index = visIds.indexOf(result.id);
                        if (index > -1) {
                            scope.query.visualizations[index] = result;
                        } else {
                            scope.query.visualizations.push(result);
                        }
                    }, function error() {
                        growl.addErrorMessage("Visualization could not be saved");
                    });
                };
            }
        }
    }]);

    directives.directive('editDashboardForm', ['$http', '$location', '$timeout', 'Dashboard', function($http, $location, $timeout, Dashboard) {
        return {
            restrict: 'E',
            scope: {
                dashboard: '='
            },
            templateUrl: '/views/edit_dashboard.html',
            replace: true,
            link: function($scope, element, attrs) {
                var gridster = element.find(".gridster ul").gridster({
                    widget_margins: [5, 5],
                    widget_base_dimensions: [260, 100],
                    min_cols: 2,
                    max_cols: 2,
                    serialize_params: function($w, wgd) {
                        return {
                            col: wgd.col,
                            row: wgd.row,
                            id: $w.data('widget-id')
                        }
                    }
                }).data('gridster');

                var gsItemTemplate = '
' +
                                 '
{name}' +
                                 '

';

                $scope.$watch('dashboard.widgets', function(widgets) {
                    $timeout(function () {
                        gridster.remove_all_widgets();

                        if (widgets && widgets.length) {
                            var layout = [];

                            _.each(widgets, function(row, rowIndex) {
                                _.each(row, function(widget, colIndex) {
                                    layout.push({
                                        id: widget.id,
                                        col: colIndex+1,
                                        row: rowIndex+1,
                                        ySize: 1,
                                        xSize: widget.width,
                                        name: widget.visualization.query.name
                                    });
                                });
                            });

                            _.each(layout, function(item) {
                                var el = gsItemTemplate.replace('{id}', item.id).replace('{name}', item.name);
                                gridster.add_widget(el, item.xSize, item.ySize, item.col, item.row);

                            });
                        }
                    });
                }, true);

                $scope.saveDashboard = function() {
                    $scope.saveInProgress = true;
                    // TODO: we should use the dashboard service here.
                    if ($scope.dashboard.id) {
                        var positions = $(element).find('.gridster ul').data('gridster').serialize();
                        var layout = [];
                        _.each(_.sortBy(positions, function (pos) {
                            return pos.row * 10 + pos.col;
                        }), function (pos) {
                            var row = pos.row - 1;
                            var col = pos.col - 1;
                            layout[row] = layout[row] || [];
                            if (col > 0 && layout[row][col - 1] == undefined) {
                                layout[row][col - 1] = pos.id;
                            } else {
                                layout[row][col] = pos.id;
                            }

                        });
                        $scope.dashboard.layout = layout;

                        layout = JSON.stringify(layout);
                        $http.post('/api/dashboards/' + $scope.dashboard.id, {'name': $scope.dashboard.name, 'layout': layout}).success(function(response) {
                            $scope.dashboard = new Dashboard(response);
                            $scope.saveInProgress = false;
                            $(element).modal('hide');
                        })
                    } else {
                        $http.post('/api/dashboards', {'name': $scope.dashboard.name}).success(function(response) {
                            $(element).modal('hide');
                            $location.path('/dashboard/' + response.slug).replace();
                        })
                    }
                }

            }
        }
    }]);

    directives.directive('newWidgetForm', ['$http', 'Query', function($http, Query) {
        return {
            restrict: 'E',
            scope: {
                dashboard: '='
            },
            templateUrl: '/views/new_widget_form.html',
            replace: true,
            link: function($scope, element, attrs) {
                $scope.widgetSizes = [{name: 'Regular', value: 1}, {name: 'Double', value: 2}];

                var reset = function() {
                    $scope.saveInProgress = false;
                    $scope.widgetSize = 1;
                    $scope.queryId = null;
                    $scope.selectedVis = null;

                }

                reset();

                $scope.loadVisualizations = function() {
                    if (!$scope.queryId) {
                        return;
                    }

                    Query.get({
                        id: $scope.queryId
                    }, function(query) {
                        if (query) {
                            $scope.query = query;
                            if(query.visualizations.length) {
                                $scope.selectedVis = query.visualizations[0];
                            }
                        }
                    });
                };

                $scope.saveWidget = function() {
                    $scope.saveInProgress = true;

                    var widget = {
                        'visualization_id': $scope.selectedVis.id,
                        'dashboard_id': $scope.dashboard.id,
                        'options': {},
                        'width': $scope.widgetSize
                    }

                    $http.post('/api/widgets', widget).success(function(response) {
                        // update dashboard layout
                        $scope.dashboard.layout = response['layout'];
                        if (response['new_row']) {
                            $scope.dashboard.widgets.push([response['widget']]);
                        } else {
                            $scope.dashboard.widgets[$scope.dashboard.widgets.length-1].push(response['widget']);
                        }

                        // close the dialog
                        $('#add_query_dialog').modal('hide');
                        reset();
                    })
                }

            }
        }
    }])

    // From: http://jsfiddle.net/joshdmiller/NDFHg/
    directives.directive('editInPlace', function () {
        return {
            restrict: 'E',
            scope: {
                value: '=',
                ignoreBlanks: '=',
                editable: '='
            },
            template: function(tElement, tAttrs) {
                var elType = tAttrs.editor || 'input';
                var placeholder = tAttrs.placeholder || 'Click to edit';
                return '' +
                       '' + placeholder + '' +
                       '<{elType} ng-model="value" class="form-control" rows="2"></{elType}>'.replace('{elType}', elType);
            },
            link: function ($scope, element, attrs) {
                // Let's get a reference to the input element, as we'll want to reference it.
                var inputElement = angular.element(element.children()[2]);

                // This directive should have a set class so we can style it.
                element.addClass('edit-in-place');

                // Initially, we're not editing.
                $scope.editing = false;

                // ng-click handler to activate edit-in-place
                $scope.edit = function () {
                    if ($scope.ignoreBlanks) {
                        $scope.oldValue = $scope.value;
                    }

                    $scope.editing = true;

                    // We control display through a class on the directive itself. See the CSS.
                    element.addClass('active');

                    // And we must focus the element.
                    // `angular.element()` provides a chainable array, like jQuery so to access a native DOM function,
                    // we have to reference the first element in the array.
                    inputElement[0].focus();
                };

                $(inputElement).blur(function() {
                    if ($scope.ignoreBlanks && _.isEmpty($scope.value)) {
                        $scope.value = $scope.oldValue;
                    }
                    $scope.editing = false;
                    element.removeClass('active');
                })
            }
        };
    });

    // http://stackoverflow.com/a/17904092/1559840
    directives.directive('jsonText', function() {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function(scope, element, attr, ngModel) {
              function into(input) {
                return JSON.parse(input);
              }
              function out(data) {
                return JSON.stringify(data, undefined, 2);
              }
              ngModel.$parsers.push(into);
              ngModel.$formatters.push(out);

            }
        };
    });

    directives.directive('rdTimer', ['$timeout', function ($timeout) {
        return {
            restrict: 'E',
            scope: { timestamp: '=' },
            template: '{{currentTime}}',
            controller: ['$scope' ,function ($scope) {
                $scope.currentTime = "00:00:00";
                var currentTimeout = null;

                var updateTime = function() {
                    $scope.currentTime = moment(moment() - moment($scope.timestamp)).utc().format("HH:mm:ss")
                    currentTimeout = $timeout(updateTime, 1000);
                }

                var cancelTimer = function() {
                    if (currentTimeout) {
                        $timeout.cancel(currentTimeout);
                        currentTimeout = null;
                    }
                }

                updateTime();

                $scope.$on('$destroy', function () {
                    cancelTimer();
                });
            }]
        };
    }]);
})();
<|endoftext|>