<commit_before>/*jshint strict: false, sub: true */
/*global print */
'use strict';

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////

const internal = require("internal");
const fs = require("fs");
const tasks = require("org/arangodb/tasks");

const _ = require("lodash");

const executeExternalAndWait = require("internal").executeExternalAndWait;

const db = internal.db;
const sleep = internal.sleep;

const optsDefault = {
  duration: 60, // in minutes
  gnuplot: false,
  results: "results",
  runId: "run"
};

////////////////////////////////////////////////////////////////////////////////
/// @brief create image using gnuplot
////////////////////////////////////////////////////////////////////////////////

function gnuplot() {
  executeExternalAndWait("gnuplot", "out/kills.plot");
}

////////////////////////////////////////////////////////////////////////////////
/// @brief statistics generator
////////////////////////////////////////////////////////////////////////////////

let statisticsInitialized = false;

const killsLog = fs.join("out", "kills.csv");
const types = ["inserter", "updater", "remover", "killer"];

function statistics(opts) {
  if (!statisticsInitialized) {
    fs.makeDirectoryRecursive("out");

    fs.write(killsLog, "# " + types.join("\t") + "\n");

    statisticsInitialized = true;
  }

  const results = opts.results;

  let runtime = Math.round(((new Date()) - opts.startTime) / 1000);
  let line = [runtime];

  for (let i = 0; i < types.length; ++i) {
    const s = db._query(
      `
       FOR u IN @@results
         FILTER u.type == @type
         RETURN u.statistics
      `, {
        '@results': results,
        'type': types[i]
      }).toArray()[0];

    if (s !== undefined) {
      line.push(s.count);
      line.push(s.success);
      line.push(s.failures);
    } else {
      line.push(0);
      line.push(0);
      line.push(0);
    }
  }

  fs.append(killsLog, line.join("\t") + "\n");
}

////////////////////////////////////////////////////////////////////////////////
/// @brief INSERTER
////////////////////////////////////////////////////////////////////////////////

exports.inserter = function(opts) {
  const runId = opts.runId;

  const duration = opts.duration;
  const start = Date.now();
  const end = start + 1000 * 60 * duration;

  const results = opts.results;
  const r = db._collection(results);

  try {
    r.remove(runId);
  } catch (err) {}

  r.save({
    _key: runId,
    started: true,
    finished: false,
    startDate: start,
    endDate: end,
    type: "inserter",
    statistics: {
      count: 0,
      success: 0,
      failures: 0
    }
  });

  let count = 0;
  let success = 0;
  let failures = 0;
  let lastErr = "";

  while (true) {
    ++count;

    if (count % 1000 === 0) {
      r.update(runId, {
        statistics: {
          count: count,
          success: success,
          failures: failures
        },
        lastError: lastErr
      });
    }

    let c = Math.floor(Math.random() * 8) + 2;
    let q = `
      FOR doc IN 1..@c
        INSERT {
          _from: CONCAT("posts/test", doc),
          _to: CONCAT("posts/test", @c),
          value: doc
        }
        IN edges`;

    try {
      db._query({
        query: q,
        bindVars: {
          c
        }
      });

      ++success;
    } catch (err) {
      if (err.errorNum !== 1500) {
        lastErr = String(err);
        print(err);
        ++failures;
      }
    }
  }

  r.update(runId, {
    finished: true,
    statistics: {
      count: count,
      success: success,
      failures: failures
    }
  });
};

////////////////////////////////////////////////////////////////////////////////
/// @brief UPDATER
////////////////////////////////////////////////////////////////////////////////

exports.updater = function(opts) {
  const runId = opts.runId;

  const duration = opts.duration;
  const start = Date.now();
  const end = start + 1000 * 60 * duration;

  const results = opts.results;
  const r = db._collection(results);

  try {
    r.remove(runId);
  } catch (err) {}

  r.save({
    _key: runId,
    started: true,
    finished: false,
    startDate: start,
    endDate: end,
    type: "updater",
    statistics: {
      count: 0,
      success: 0,
      failures: 0
    }
  });

  let count = 0;
  let success = 0;
  let failures = 0;
  let lastErr = "";

  while (true) {
    ++count;

    if (count % 1000 === 0) {
      r.update(runId, {
        statistics: {
          count: count,
          success: success,
          failures: failures
        }
      });
    }

    let c = Math.floor(Math.random() * 8) + 2;
    let q = `
      FOR doc IN edges
        SORT RAND()
        LIMIT @c
        UPDATE doc WITH { value: doc.value + 1 }
        IN edges`;

    try {
      db._query({
        query: q,
        bindVars: {
          c
        }
      });

      success++;
    } catch (err) {
      if (err.errorNum !== 1500) {
        lastErr = String(err);
        print(err);
        ++failures;
      }
    }
  }

  r.update(runId, {
    finished: true,
    statistics: {
      count: count,
      success: success,
      failures: failures
    }
  });
};

////////////////////////////////////////////////////////////////////////////////
/// @brief REOMVER
////////////////////////////////////////////////////////////////////////////////

exports.remover = function(opts) {
  const runId = opts.runId;

  const duration = opts.duration;
  const start = Date.now();
  const end = start + 1000 * 60 * duration;

  const results = opts.results;
  const r = db._collection(results);

  try {
    r.remove(runId);
  } catch (err) {}

  r.save({
    _key: runId,
    started: true,
    finished: false,
    startDate: start,
    endDate: end,
    type: "remover",
    statistics: {
      count: 0,
      success: 0,
      failures: 0
    }
  });

  let count = 0;
  let success = 0;
  let failures = 0;
  let lastErr = "";

  while (true) {
    ++count;

    if (count % 1000 === 0) {
      r.update(runId, {
        statistics: {
          count: count,
          success: success,
          failures: failures
        }
      });
    }

    let c = Math.floor(Math.random() * 8) + 2;
    let q = `
      FOR doc IN edges
        SORT RAND()
        LIMIT @c
        REMOVE doc._key
        IN edges`;

    try {
      db._query({
        query: q,
        bindVars: {
          c
        }
      });

      success++;
    } catch (err) {
      if (err.errorNum !== 1500) {
        lastErr = String(err);
        print(err);
        ++failures;
      }
    }
  }

  r.update(runId, {
    finished: true,
    statistics: {
      count: count,
      success: success,
      failures: failures
    }
  });
};

////////////////////////////////////////////////////////////////////////////////
/// @brief KILLER
////////////////////////////////////////////////////////////////////////////////

exports.killer = function(opts) {
  const runId = opts.runId;

  const duration = opts.duration;
  const start = Date.now();
  const end = start + 1000 * 60 * duration;

  const results = opts.results;
  const r = db._collection(results);

  try {
    r.remove(runId);
  } catch (err) {}

  r.save({
    _key: runId,
    started: true,
    finished: false,
    startDate: start,
    endDate: end,
    type: "killer",
    statistics: {
      count: 0,
      success: 0,
      failures: 0
    }
  });

  let count = 0;
  let success = 0;
  let failures = 0;
  let lastErr = "";

  const queries = require("org/arangodb/aql/queries");

  while (true) {
    ++count;

    if (count % 100 === 0) {
      r.update(runId, {
        statistics: {
          count: count,
          success: success,
          failures: failures
        }
      });
    }

    queries.current().forEach(function(q) {
      if (q.query.indexOf("edges") !== -1) {
        try {
          queries.kill(q.id);
          success++;
        } catch (err) {
          if (err.errorNum !== 1591) {
            lastErr = String(err);
            print(err);
          }
          ++failures;
        }
      }
    });

    internal.wait(Math.random() * 0.1, false);
  }

  r.update(runId, {
    finished: true,
    statistics: {
      count: count,
      success: success,
      failures: failures
    }
  });
};

////////////////////////////////////////////////////////////////////////////////
/// @brief killing
////////////////////////////////////////////////////////////////////////////////

exports.killingParallel = function(opts) {
  _.defaults(opts, optsDefault);

  // start time
  opts.startTime = new Date();

  // create the test collections
  db._drop("edges");
  db._createEdgeCollection("edges");

  db._drop("posts");
  db._create("posts");

  // create the "results" collection
  const results = opts.results;
  db._drop(results);
  db._create(results);

  // create output directory
  fs.makeDirectoryRecursive("out");

  // start worker
  const w = [
    function(params) {
      require("./js/server/tests/stress/killingQueries").inserter(params);
    },
    function(params) {
      require("./js/server/tests/stress/killingQueries").updater(params);
    },
    function(params) {
      require("./js/server/tests/stress/killingQueries").remover(params);
    },
    function(params) {
      require("./js/server/tests/stress/killingQueries").killer(params);
    }
  ];

  for (let i = 0; i < w.length; ++i) {
    const cmd = w[i];
    let o = JSON.parse(JSON.stringify(opts));

    o.runId = "run_" + i;

    tasks.register({
      id: "stress" + i,
      name: "stress test " + i,
      offset: i,
      params: o,
      command: cmd
    });
  }

  // wait for a result
  const countDone = function() {
    const a = db._query("FOR u IN @@results FILTER u.finished RETURN 1", {
      '@results': 'results'
    });

    const b = db._query("FOR u IN @@results FILTER u.started RETURN 1", {
      '@results': 'results'
    });

    return a.count() === b.count();
  };

  let m = 0;

  for (let i = 0; i < 10; ++i) {
    m = db._query("FOR u IN @@results FILTER u.started RETURN 1", {
      '@results': 'results'
    }).count();

    print(m + " workers are up and running");

    if (m === w.length) {
      break;
    }

    sleep(30);
  }

  if (m < w.length) {
    print("cannot start enough workers (want", w.length + ",", "got", m + "),",
      "please check number V8 contexts");
    throw new Error("cannot start workers");
  }

  if (opts.gnuplot) {
    fs.write(fs.join("out", "kills.plot"),
      `
set terminal png size 1024,1024
set size ratio 0.3
set output "out/kills.png"

set multiplot layout 4, 1 title "Killing Queries Stress Test" font ",14"

set autoscale
set logscale y
set key outside
set xlabel "runtime in seconds"

set ylabel "inserter"
plot \
  "out/kills.csv" using 1:2 title "count" with lines lw 2, \
  '' using 1:3 title "success" with lines, \
  '' using 1:4 title "failures" with lines

set ylabel "updater"
plot \
  "out/kills.csv" using 1:5 title "count" with lines lw 2, \
  '' using 1:6 title "success" with lines, \
  '' using 1:7 title "failures" with lines

set ylabel "remover"
plot \
  "out/kills.csv" using 1:8 title "count" with lines lw 2, \
  '' using 1:9 title "success" with lines, \
  '' using 1:10 title "failures" with lines

set ylabel "killer"
plot \
  "out/kills.csv" using 1:11 title "count" with lines lw 2, \
  '' using 1:12 title "success" with lines, \
  '' using 1:13 title "failures" with lines
`);
  }

  let count = 0;

  while (!countDone()) {
    ++count;
    statistics(opts);

    if (opts.gnuplot && count % 6 === 0) {
      print("generating image");
      gnuplot();
    }

    sleep(10);
  }

  statistics(opts);

  if (opts.gnuplot) {
    gnuplot();
  }

  return true;
};
<commit_msg>added duration<commit_after>/*jshint strict: false, sub: true */
/*global print */
'use strict';

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
////////////////////////////////////////////////////////////////////////////////

const internal = require("internal");
const fs = require("fs");
const tasks = require("org/arangodb/tasks");

const _ = require("lodash");

const executeExternalAndWait = require("internal").executeExternalAndWait;

const db = internal.db;
const sleep = internal.sleep;

const optsDefault = {
  duration: 60, // in minutes
  gnuplot: false,
  results: "results",
  runId: "run"
};

////////////////////////////////////////////////////////////////////////////////
/// @brief create image using gnuplot
////////////////////////////////////////////////////////////////////////////////

function gnuplot() {
  executeExternalAndWait("gnuplot", "out/kills.plot");
}

////////////////////////////////////////////////////////////////////////////////
/// @brief statistics generator
////////////////////////////////////////////////////////////////////////////////

let statisticsInitialized = false;

const killsLog = fs.join("out", "kills.csv");
const types = ["inserter", "updater", "remover", "killer"];

function statistics(opts) {
  if (!statisticsInitialized) {
    fs.makeDirectoryRecursive("out");

    fs.write(killsLog, "# " + types.join("\t") + "\n");

    statisticsInitialized = true;
  }

  const results = opts.results;

  let runtime = Math.round(((new Date()) - opts.startTime) / 1000);
  let line = [runtime];

  for (let i = 0; i < types.length; ++i) {
    const s = db._query(
      `
       FOR u IN @@results
         FILTER u.type == @type
         RETURN u.statistics
      `, {
        '@results': results,
        'type': types[i]
      }).toArray()[0];

    if (s !== undefined) {
      line.push(s.count);
      line.push(s.success);
      line.push(s.failures);
    } else {
      line.push(0);
      line.push(0);
      line.push(0);
    }
  }

  fs.append(killsLog, line.join("\t") + "\n");
}

////////////////////////////////////////////////////////////////////////////////
/// @brief INSERTER
////////////////////////////////////////////////////////////////////////////////

exports.inserter = function(opts) {
  const runId = opts.runId;

  const duration = opts.duration;
  const start = Date.now();
  const end = start + 1000 * 60 * duration;

  const results = opts.results;
  const r = db._collection(results);

  try {
    r.remove(runId);
  } catch (err) {}

  r.save({
    _key: runId,
    started: true,
    finished: false,
    startDate: start,
    endDate: end,
    type: "inserter",
    statistics: {
      count: 0,
      success: 0,
      failures: 0
    }
  });

  let count = 0;
  let success = 0;
  let failures = 0;
  let lastErr = "";

  while (true) {
    ++count;

    if (count % 1000 === 0) {
      r.update(runId, {
        statistics: {
          count: count,
          success: success,
          failures: failures
        },
        lastError: lastErr
      });
    }

    let c = Math.floor(Math.random() * 8) + 2;
    let q = `
      FOR doc IN 1..@c
        INSERT {
          _from: CONCAT("posts/test", doc),
          _to: CONCAT("posts/test", @c),
          value: doc
        }
        IN edges`;

    try {
      db._query({
        query: q,
        bindVars: {
          c
        }
      });

      ++success;
    } catch (err) {
      if (err.errorNum !== 1500) {
        lastErr = String(err);
        print(err);
        ++failures;
      }
    }

    if (Date.now() > end) {
      break;
    }
  }

  r.update(runId, {
    finished: true,
    statistics: {
      count: count,
      success: success,
      failures: failures
    }
  });
};

////////////////////////////////////////////////////////////////////////////////
/// @brief UPDATER
////////////////////////////////////////////////////////////////////////////////

exports.updater = function(opts) {
  const runId = opts.runId;

  const duration = opts.duration;
  const start = Date.now();
  const end = start + 1000 * 60 * duration;

  const results = opts.results;
  const r = db._collection(results);

  try {
    r.remove(runId);
  } catch (err) {}

  r.save({
    _key: runId,
    started: true,
    finished: false,
    startDate: start,
    endDate: end,
    type: "updater",
    statistics: {
      count: 0,
      success: 0,
      failures: 0
    }
  });

  let count = 0;
  let success = 0;
  let failures = 0;
  let lastErr = "";

  while (true) {
    ++count;

    if (count % 1000 === 0) {
      r.update(runId, {
        statistics: {
          count: count,
          success: success,
          failures: failures
        }
      });
    }

    let c = Math.floor(Math.random() * 8) + 2;
    let q = `
      FOR doc IN edges
        SORT RAND()
        LIMIT @c
        UPDATE doc WITH { value: doc.value + 1 }
        IN edges`;

    try {
      db._query({
        query: q,
        bindVars: {
          c
        }
      });

      success++;
    } catch (err) {
      if (err.errorNum !== 1500) {
        lastErr = String(err);
        print(err);
        ++failures;
      }
    }

    if (Date.now() > end) {
      break;
    }
  }

  r.update(runId, {
    finished: true,
    statistics: {
      count: count,
      success: success,
      failures: failures
    }
  });
};

////////////////////////////////////////////////////////////////////////////////
/// @brief REOMVER
////////////////////////////////////////////////////////////////////////////////

exports.remover = function(opts) {
  const runId = opts.runId;

  const duration = opts.duration;
  const start = Date.now();
  const end = start + 1000 * 60 * duration;

  const results = opts.results;
  const r = db._collection(results);

  try {
    r.remove(runId);
  } catch (err) {}

  r.save({
    _key: runId,
    started: true,
    finished: false,
    startDate: start,
    endDate: end,
    type: "remover",
    statistics: {
      count: 0,
      success: 0,
      failures: 0
    }
  });

  let count = 0;
  let success = 0;
  let failures = 0;
  let lastErr = "";

  while (true) {
    ++count;

    if (count % 1000 === 0) {
      r.update(runId, {
        statistics: {
          count: count,
          success: success,
          failures: failures
        }
      });
    }

    let c = Math.floor(Math.random() * 8) + 2;
    let q = `
      FOR doc IN edges
        SORT RAND()
        LIMIT @c
        REMOVE doc._key
        IN edges`;

    try {
      db._query({
        query: q,
        bindVars: {
          c
        }
      });

      success++;
    } catch (err) {
      if (err.errorNum !== 1500) {
        lastErr = String(err);
        print(err);
        ++failures;
      }
    }

    if (Date.now() > end) {
      break;
    }
  }

  r.update(runId, {
    finished: true,
    statistics: {
      count: count,
      success: success,
      failures: failures
    }
  });
};

////////////////////////////////////////////////////////////////////////////////
/// @brief KILLER
////////////////////////////////////////////////////////////////////////////////

exports.killer = function(opts) {
  const runId = opts.runId;

  const duration = opts.duration;
  const start = Date.now();
  const end = start + 1000 * 60 * duration;

  const results = opts.results;
  const r = db._collection(results);

  try {
    r.remove(runId);
  } catch (err) {}

  r.save({
    _key: runId,
    started: true,
    finished: false,
    startDate: start,
    endDate: end,
    type: "killer",
    statistics: {
      count: 0,
      success: 0,
      failures: 0
    }
  });

  let count = 0;
  let success = 0;
  let failures = 0;
  let lastErr = "";

  const queries = require("org/arangodb/aql/queries");

  while (true) {
    ++count;

    if (count % 100 === 0) {
      r.update(runId, {
        statistics: {
          count: count,
          success: success,
          failures: failures
        }
      });
    }

    queries.current().forEach(function(q) {
      if (q.query.indexOf("edges") !== -1) {
        try {
          queries.kill(q.id);
          success++;
        } catch (err) {
          if (err.errorNum !== 1591) {
            lastErr = String(err);
            print(err);
          }
          ++failures;
        }
      }
    });

    if (Date.now() > end) {
      break;
    }

    internal.wait(Math.random() * 0.1, false);
  }

  r.update(runId, {
    finished: true,
    statistics: {
      count: count,
      success: success,
      failures: failures
    }
  });
};

////////////////////////////////////////////////////////////////////////////////
/// @brief killing
////////////////////////////////////////////////////////////////////////////////

exports.killingParallel = function(opts) {
  _.defaults(opts, optsDefault);

  // start time
  opts.startTime = new Date();

  // create the test collections
  db._drop("edges");
  db._createEdgeCollection("edges");

  db._drop("posts");
  db._create("posts");

  // create the "results" collection
  const results = opts.results;
  db._drop(results);
  db._create(results);

  // create output directory
  fs.makeDirectoryRecursive("out");

  // start worker
  const w = [
    function(params) {
      require("./js/server/tests/stress/killingQueries").inserter(params);
    },
    function(params) {
      require("./js/server/tests/stress/killingQueries").updater(params);
    },
    function(params) {
      require("./js/server/tests/stress/killingQueries").remover(params);
    },
    function(params) {
      require("./js/server/tests/stress/killingQueries").killer(params);
    }
  ];

  for (let i = 0; i < w.length; ++i) {
    const cmd = w[i];
    let o = JSON.parse(JSON.stringify(opts));

    o.runId = "run_" + i;

    tasks.register({
      id: "stress" + i,
      name: "stress test " + i,
      offset: i,
      params: o,
      command: cmd
    });
  }

  // wait for a result
  const countDone = function() {
    const a = db._query("FOR u IN @@results FILTER u.finished RETURN 1", {
      '@results': 'results'
    });

    const b = db._query("FOR u IN @@results FILTER u.started RETURN 1", {
      '@results': 'results'
    });

    return a.count() === b.count();
  };

  let m = 0;

  for (let i = 0; i < 10; ++i) {
    m = db._query("FOR u IN @@results FILTER u.started RETURN 1", {
      '@results': 'results'
    }).count();

    print(m + " workers are up and running");

    if (m === w.length) {
      break;
    }

    sleep(30);
  }

  if (m < w.length) {
    print("cannot start enough workers (want", w.length + ",", "got", m + "),",
      "please check number V8 contexts");
    throw new Error("cannot start workers");
  }

  if (opts.gnuplot) {
    fs.write(fs.join("out", "kills.plot"),
      `
set terminal png size 1024,1024
set size ratio 0.3
set output "out/kills.png"

set multiplot layout 4, 1 title "Killing Queries Stress Test" font ",14"

set autoscale
set logscale y
set key outside
set xlabel "runtime in seconds"

set ylabel "inserter"
plot \
  "out/kills.csv" using 1:2 title "count" with lines lw 2, \
  '' using 1:3 title "success" with lines, \
  '' using 1:4 title "failures" with lines

set ylabel "updater"
plot \
  "out/kills.csv" using 1:5 title "count" with lines lw 2, \
  '' using 1:6 title "success" with lines, \
  '' using 1:7 title "failures" with lines

set ylabel "remover"
plot \
  "out/kills.csv" using 1:8 title "count" with lines lw 2, \
  '' using 1:9 title "success" with lines, \
  '' using 1:10 title "failures" with lines

set ylabel "killer"
plot \
  "out/kills.csv" using 1:11 title "count" with lines lw 2, \
  '' using 1:12 title "success" with lines, \
  '' using 1:13 title "failures" with lines
`);
  }

  let count = 0;

  while (!countDone()) {
    ++count;
    statistics(opts);

    if (opts.gnuplot && count % 6 === 0) {
      print("generating image");
      gnuplot();
    }

    sleep(10);
  }

  statistics(opts);

  if (opts.gnuplot) {
    gnuplot();
  }

  return true;
};
<|endoftext|>


<commit_before>'use strict';

// Vocablists controller
angular.module('vocablists').
  controller('UploadController',
    ['$scope', 'Upload', '$timeout',
      function($scope, Upload, $timeout) {
        $scope.upload = function(file, errFiles) {
          $scope.f = file;
          $scope.errFile = errFiles && errFiles[0];
          if (file) {
            file.upload = Upload.upload({
              url: 'vocablists/upload',
              data: {file: file}
            });

            file.upload.then(
              function(response) {
                $timeout(function() {
                    file.result = response.data;
                  }
                );
              },
              function(response) {
                if (response.status > 0) {
                  $scope.errorMsg = response.status + ': ' + response.data;
                }
              },
              function(evt) {
                file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
              }
            );
          } else {
            alert('No file');
          }
        };
      }
]);
<commit_msg>Adds a redirect after successful upload<commit_after>'use strict';

// Vocablists controller
angular.module('vocablists').
  controller('UploadController',
    ['$scope', 'Upload', '$timeout', '$location',
      function($scope, Upload, $timeout, $location) {
        $scope.upload = function(file, errFiles) {
          $scope.f = file;
          $scope.errFile = errFiles && errFiles[0];
          if (file) {
            file.upload = Upload.upload({
              url: 'vocablists/upload',
              data: {file: file}
            });

            file.upload.then(
              function(response) {
                $timeout(function() { file.result = response.data; });
                $location.path('vocablists/lists');
              },
              function(response) {
                if (response.status > 0) {
                  $scope.errorMsg = response.status + ': ' + response.data;
                }
              },
              function(evt) {
                file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
              }
            );
          } else {
            alert('No file');
          }
        };
      }
]);
<|endoftext|>


<commit_before>'use strict';

// As of v14, Node.js does not exit when there is an unhandled Promise rejection. Convert an
// unhandled rejection into an uncaught exception, which does cause Node.js to exit.
process.on('unhandledRejection', (err) => { throw err; });

const async = require('async');
const swd = require('selenium-webdriver');
const swdChrome = require('selenium-webdriver/chrome');

const isAdminRunner = process.argv[2] === 'admin';

const colorSubst = {
  red: '\x1B[31m',
  yellow: '\x1B[33m',
  green: '\x1B[32m',
  clear: '\x1B[39m',
};
const colorRegex = new RegExp(`\\[(${Object.keys(colorSubst).join('|')})\\]`, 'g');

const log = (msg, pfx = '') => {
  console.log(`${pfx}${msg.replace(colorRegex, (m, p1) => colorSubst[p1])}`);
};

const finishedRegex = /FINISHED.*[0-9]+ tests passed, ([0-9]+) tests failed/;

const sauceTestWorker = async.queue(async ({name, pfx, testSettings}) => {
  const chromeOptions = new swdChrome.Options()
      .addArguments('use-fake-device-for-media-stream');
  const driver = await new swd.Builder()
      .usingServer('https://ondemand.saucelabs.com/wd/hub')
      .withCapabilities(Object.assign({
        'sauce:options': {
          username: process.env.SAUCE_USERNAME,
          accessKey: process.env.SAUCE_ACCESS_KEY,
          name: [process.env.GIT_HASH].concat(process.env.SAUCE_NAME || [], name).join(' - '),
          public: true,
          build: process.env.GIT_HASH,
          // console.json can be downloaded via saucelabs,
          // don't know how to print them into output of the tests
          extendedDebugging: true,
          tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER,
        },
      }, testSettings))
      .setChromeOptions(chromeOptions)
      .build();
  const url = `https://saucelabs.com/jobs/${(await driver.getSession()).getId()}`;
  try {
    await driver.get('http://localhost:9001/tests/frontend/');
    log(`Remote sauce test started! ${url}`, pfx);
    // @TODO this should be configured in testSettings, see
    // https://wiki.saucelabs.com/display/DOCS/Test+Configuration+Options#TestConfigurationOptions-Timeouts
    const deadline = Date.now() + 14.5 * 60 * 1000; // Slightly less than overall test timeout.
    // how many characters of the log have been sent to travis
    let logIndex = 0;
    const remoteFn = (skipChars) => {
      const console = document.getElementById('console'); // eslint-disable-line no-undef
      if (console == null) return '';
      let text = '';
      for (const n of console.childNodes) {
        if (n.nodeType === n.TEXT_NODE) text += n.data;
      }
      return text.substring(skipChars);
    };
    while (true) {
      const consoleText = await driver.executeScript(remoteFn, logIndex);
      (consoleText ? consoleText.split('\n') : []).forEach((line) => log(line, pfx));
      logIndex += consoleText.length;
      const [finished, nFailedStr] = consoleText.match(finishedRegex) || [];
      if (finished) {
        if (nFailedStr !== '0') process.exitCode = 1;
        break;
      }
      if (Date.now() >= deadline) {
        log('[red]FAILED[clear] allowed test duration exceeded');
        process.exitCode = 1;
        break;
      }
      await new Promise((resolve) => setTimeout(resolve, 5000));
    }
  } finally {
    log(`Remote sauce test finished! ${url}`, pfx);
    await driver.quit();
  }
}, 6); // run 6 tests in parrallel

Promise.all([
  {
    platformName: 'macOS 11.00',
    browserName: 'safari',
    browserVersion: 'latest',
  },
  ...(isAdminRunner ? [] : [
    {
      platformName: 'Windows 10',
      browserName: 'firefox',
      browserVersion: 'latest',
    },
    {
      platformName: 'Windows 10',
      browserName: 'MicrosoftEdge',
      browserVersion: 'latest',
    },
    {
      platformName: 'Windows 10',
      browserName: 'chrome',
      browserVersion: 'latest',
    },
    {
      platformName: 'Windows 7',
      browserName: 'chrome',
      browserVersion: '55.0',
    },
  ]),
].map(async (testSettings) => {
  const name =
      `${testSettings.browserName} ${testSettings.browserVersion}, ${testSettings.platformName}`;
  const pfx = `[${name}] `;
  try {
    await sauceTestWorker.push({name, pfx, testSettings});
  } catch (err) {
    log(`[red]FAILED[clear] ${err.stack || err}`, pfx);
    process.exitCode = 1;
  }
}));
<commit_msg>tests: Also pass `--use-fake-ui-for-media-stream` to Chrome<commit_after>'use strict';

// As of v14, Node.js does not exit when there is an unhandled Promise rejection. Convert an
// unhandled rejection into an uncaught exception, which does cause Node.js to exit.
process.on('unhandledRejection', (err) => { throw err; });

const async = require('async');
const swd = require('selenium-webdriver');
const swdChrome = require('selenium-webdriver/chrome');

const isAdminRunner = process.argv[2] === 'admin';

const colorSubst = {
  red: '\x1B[31m',
  yellow: '\x1B[33m',
  green: '\x1B[32m',
  clear: '\x1B[39m',
};
const colorRegex = new RegExp(`\\[(${Object.keys(colorSubst).join('|')})\\]`, 'g');

const log = (msg, pfx = '') => {
  console.log(`${pfx}${msg.replace(colorRegex, (m, p1) => colorSubst[p1])}`);
};

const finishedRegex = /FINISHED.*[0-9]+ tests passed, ([0-9]+) tests failed/;

const sauceTestWorker = async.queue(async ({name, pfx, testSettings}) => {
  const chromeOptions = new swdChrome.Options()
      .addArguments('use-fake-device-for-media-stream', 'use-fake-ui-for-media-stream');
  const driver = await new swd.Builder()
      .usingServer('https://ondemand.saucelabs.com/wd/hub')
      .withCapabilities(Object.assign({
        'sauce:options': {
          username: process.env.SAUCE_USERNAME,
          accessKey: process.env.SAUCE_ACCESS_KEY,
          name: [process.env.GIT_HASH].concat(process.env.SAUCE_NAME || [], name).join(' - '),
          public: true,
          build: process.env.GIT_HASH,
          // console.json can be downloaded via saucelabs,
          // don't know how to print them into output of the tests
          extendedDebugging: true,
          tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER,
        },
      }, testSettings))
      .setChromeOptions(chromeOptions)
      .build();
  const url = `https://saucelabs.com/jobs/${(await driver.getSession()).getId()}`;
  try {
    await driver.get('http://localhost:9001/tests/frontend/');
    log(`Remote sauce test started! ${url}`, pfx);
    // @TODO this should be configured in testSettings, see
    // https://wiki.saucelabs.com/display/DOCS/Test+Configuration+Options#TestConfigurationOptions-Timeouts
    const deadline = Date.now() + 14.5 * 60 * 1000; // Slightly less than overall test timeout.
    // how many characters of the log have been sent to travis
    let logIndex = 0;
    const remoteFn = (skipChars) => {
      const console = document.getElementById('console'); // eslint-disable-line no-undef
      if (console == null) return '';
      let text = '';
      for (const n of console.childNodes) {
        if (n.nodeType === n.TEXT_NODE) text += n.data;
      }
      return text.substring(skipChars);
    };
    while (true) {
      const consoleText = await driver.executeScript(remoteFn, logIndex);
      (consoleText ? consoleText.split('\n') : []).forEach((line) => log(line, pfx));
      logIndex += consoleText.length;
      const [finished, nFailedStr] = consoleText.match(finishedRegex) || [];
      if (finished) {
        if (nFailedStr !== '0') process.exitCode = 1;
        break;
      }
      if (Date.now() >= deadline) {
        log('[red]FAILED[clear] allowed test duration exceeded');
        process.exitCode = 1;
        break;
      }
      await new Promise((resolve) => setTimeout(resolve, 5000));
    }
  } finally {
    log(`Remote sauce test finished! ${url}`, pfx);
    await driver.quit();
  }
}, 6); // run 6 tests in parrallel

Promise.all([
  {
    platformName: 'macOS 11.00',
    browserName: 'safari',
    browserVersion: 'latest',
  },
  ...(isAdminRunner ? [] : [
    {
      platformName: 'Windows 10',
      browserName: 'firefox',
      browserVersion: 'latest',
    },
    {
      platformName: 'Windows 10',
      browserName: 'MicrosoftEdge',
      browserVersion: 'latest',
    },
    {
      platformName: 'Windows 10',
      browserName: 'chrome',
      browserVersion: 'latest',
    },
    {
      platformName: 'Windows 7',
      browserName: 'chrome',
      browserVersion: '55.0',
    },
  ]),
].map(async (testSettings) => {
  const name =
      `${testSettings.browserName} ${testSettings.browserVersion}, ${testSettings.platformName}`;
  const pfx = `[${name}] `;
  try {
    await sauceTestWorker.push({name, pfx, testSettings});
  } catch (err) {
    log(`[red]FAILED[clear] ${err.stack || err}`, pfx);
    process.exitCode = 1;
  }
}));
<|endoftext|>


<commit_before>var util = require('util');

/**
 * Base model class. Provides common methods for models.
 */
module.exports = Base;

/**
 * Base model constructor.
 * @constructor
 */
function Base() {}

/**
 * Default 'where' value for SELECT statements.
 * @const
 * @private {string}
 */
Base.DEFAULT_WHERE_VALUE_ = '1 = 1';

/**
 * Error message indicating that there is no query defined in the model.
 * @const
 * @private {string}
 */
Base.DEFAULT_MISSING_QUERY_MESSAGE_ =
    'Could not find a query for this action: ';

/**
 * Finds all records that match the given parameters.
 * @param {Function} cb Callback function to fire when done.
 * @return {Function(string, Array)} Callback function.
 */
Base.prototype.find = function(cb) {
  var query = this.getQuery('find');
  if (!query) {
    return cb(Base.DEFAULT_MISSING_QUERY_MESSAGE_ + 'find.', null);
  }
  var columns = this.getColumns();
  var where = this.getQueryObject() || Base.DEFAULT_WHERE_VALUE_;
  this.select(query, columns, where, function(err, results) {
    return cb(err, results || []);
  });
};

/**
 * Finds one record that matches the given parameters.
 * @param {Function} cb Callback function to fire when done.
 * @return {Function(string, Object)} Callback function.
 */
Base.prototype.findOne = function(cb) {
  var query = this.getQuery('findOne');
  if (!query) {
    return cb(Base.DEFAULT_MISSING_QUERY_MESSAGE_ + 'findOne.', null);
  }
  var columns = this.getColumns();
  var where = this.getQueryObject(this.resource) || Base.DEFAULT_WHERE_VALUE_;
  this.select(query, columns, where, function(err, results) {
    return cb(err, results ? results[0] : null);
  });
};

/**
 * Checks to see if a record exists, and attempts to create one if it does not.
 * The initial resource (used for `find` query) should be initialized before
 * invoking this method, and the supplied resource should be passed as the first
 * param.
 * @param {Object} resource The resource/record to create if one does not exist.
 * @param {Function(string, Object)} cb Callback function to fire when done.
 */
Base.prototype.findOrCreate = function(resource, cb) {
  this.findOne(function(err, result) {
    if (err || result) {
      cb(err, result);
    } else {
      this.resource = resource;
      this.insert(function(err, result) {
        err = err ? util.format(
            'There was an error creating the %s: %s',
            this.getTable() || 'record', err) : false;
        result = result || null;
        cb(err, result);
      });
    }
  }.bind(this));
};

/**
 * Inserts a record with the given parameters.
 * @param {Function} cb Callback function to fire when done.
 * @return {Function(string, Array)} Callback function.
 */
Base.prototype.insert = function(cb) {
  var self = this;
  var query = this.getQuery('insert');
  if (!query) {
    return cb(Base.DEFAULT_MISSING_QUERY_MESSAGE_ + 'insert.', null);
  }

  this.validate(function(err) {
    if (err) return cb(err, null);

    // Prepare the resource, adding any system generated values, like slug's.
    // The format it for inserting in DB.
    var resource = self.prepare();
    var insertObject = self.getQueryObject(resource) || {};

    this.db.getConnection(function(err, connection) {
      if (err) return cb(err, null);
      var q = connection.query(query, insertObject, function(err, result) {
        connection.release(); // Return this connection to the pool.
        if (err) {
          err = util.format('This %s could not be added: %s',
              self.getTable(), err);
          cb(err, null);
        } else {
          /**
           * During an insert the resource MUST be returned manually since the
           * Node-MySQL module does not return the inserted resource.
           */
          cb(err, resource);
        }
      });
      self.logQuery_(q);
    });
  });
};

/**
 * @param {Object} identifier The WHERE clause argument.
 * @param {Function} cb Callback function to fire when done.
 * @return {Function(string, Array)} Callback function.
 */
Base.prototype.update = function(identifier, cb) {
  var self = this;
  var query = this.getQuery('update');
  if (!query) {
    return cb(Base.DEFAULT_MISSING_QUERY_MESSAGE_ + ' update.', null);
  }

  this.validate(function(err) {
    if (err) return cb(err, null);

    // Prepare the resource, adding any system generated values, like slug's.
    // The format it for inserting in DB.
    var resource = self.prepare();
    var insertObject = self.getQueryObject(resource) || {};

    this.db.getConnection(function(err, connection) {
      if (err) return cb(err, null);

      var q = connection.query(
          query, [insertObject, identifier], function(err, result) {
            connection.release(); // Return this connection to the pool.
            if (err) {
              cb('This ' + self.getTable() + ' could not be updated: ' +
                 err, null);
            } else {
              cb(err, resource);
            }
          });
      self.logQuery_(q);
    });
  });
};

/**
 * Removes the resource identified by the parameters.
 * @param {Functon(<string>, <Array>)} cb Callback function to perform when
 *     done.
 */
Base.prototype.remove = function(cb) {
  var self = this;
  this.db.getConnection(function(err, connection) {
    if (err) return cb(err, null);
    var query = self.getQuery('remove');
    if (!query) {
      return cb(Base.DEFAULT_MISSING_QUERY_MESSAGE_ + ' remove.', null);
    }
    var where = self.getQueryObject(self.resource);
    var q = connection.query(query, where, function(err) {
      if (err) return cb(err, null);
      connection.release(); // Return this connection to the pool.
      if (err) {
        cb('This ' + self.getTable() + ' could not be deleted: ' + err, null);
      } else {
        cb(err);
      }
    });
    self.logQuery_(q);
  });
};

/**
 * Wrapper for SELECT statements.
 * Performs query and returns connection back to pool.
 * @param {string} query The query string to append values to.
 * @param {Object} columns The columns to retrieve in the query.
 * @param {Object} where The parameters that identify the result set.
 * @param {Functon(<string>, <Array>)} cb Callback function to perform when
 *     done.
 */
Base.prototype.select = function(query, columns, where, cb) {
  var self = this;
  this.db.getConnection(function(err, connection) {
    if (err) return cb(err, null);
    // Nesting tables allows for results like:
    //   {
    //     post: {id: '...', title: '...'},
    //     user: {id: '...', displayName: '...'}
    //   }
    var options = {sql: query, nestTables: true};
    var q = connection.query(options, [columns, where], function(err, results) {
      if (err) return cb(err, null);
      connection.release();
      cb(err, results || []);
    });
    self.logQuery_(q);
  });
};

/**
 * Validates the resource against the model's STRUCTURE.
 * @param {Functon(<Array>)} cb Callback function to perform when done.
 */
Base.prototype.validate = function(cb) {
  var resource = this.resource;
  var structure = this.getStructure();
  var errors = [];

  // TODO: Could be a MAP...
  if (structure) {
    for (var property in structure) {
      var rules = structure[property];

      // Validate Required Properties...
      if (rules['required'] && !resource[property]) {
        errors.push('The following required field is missing: ' +
            property);
      }

      // TODO: Validate Length (MIN and MAX)
      // TODO: Validate Types... (String, Number, Date, etc)...
    }
  }

  cb(errors.length ? errors : []);
};

/**
 * Converts the model resource into a query object with key:value pairs.
 * return {?Object || null} The formatted resource.
 */
Base.prototype.getQueryObject = function() {
  if (!this.resource || !Object.keys(this.resource).length) {
    return null;
  }

  var structure = this.getStructure();
  var tableName = this.getTable();
  var resource = this.resource;
  var object = {};

  var fields = Object.keys(structure) || [];
  fields.forEach(function(field) {
    if (resource[field]) {
      object[tableName + '.' + field] = resource[field];
    }
  });

  return object;
};

/**
 * Logs the assembled and escaped query after it has run.
 * Application must set `LOG QUERIES` for the logs to be displayed.
 * @param {Object} query Node-Mysql query result.
 * @private
 */
Base.prototype.logQuery_ = function(query) {
  if (this.app.get('LOG QUERIES')) {
    query = query || {};
    var message = util.format('MySQL Query:\t %s', query.sql || 'N/A');
    console.log(message);
  }
};
<commit_msg>Added the return param for a method.<commit_after>var util = require('util');

/**
 * Base model class. Provides common methods for models.
 */
module.exports = Base;

/**
 * Base model constructor.
 * @constructor
 */
function Base() {}

/**
 * Default 'where' value for SELECT statements.
 * @const
 * @private {string}
 */
Base.DEFAULT_WHERE_VALUE_ = '1 = 1';

/**
 * Error message indicating that there is no query defined in the model.
 * @const
 * @private {string}
 */
Base.DEFAULT_MISSING_QUERY_MESSAGE_ =
    'Could not find a query for this action: ';

/**
 * Finds all records that match the given parameters.
 * @param {Function} cb Callback function to fire when done.
 * @return {Function(string, Array)} Callback function.
 */
Base.prototype.find = function(cb) {
  var query = this.getQuery('find');
  if (!query) {
    return cb(Base.DEFAULT_MISSING_QUERY_MESSAGE_ + 'find.', null);
  }
  var columns = this.getColumns();
  var where = this.getQueryObject() || Base.DEFAULT_WHERE_VALUE_;
  this.select(query, columns, where, function(err, results) {
    return cb(err, results || []);
  });
};

/**
 * Finds one record that matches the given parameters.
 * @param {Function} cb Callback function to fire when done.
 * @return {Function(string, Object)} Callback function.
 */
Base.prototype.findOne = function(cb) {
  var query = this.getQuery('findOne');
  if (!query) {
    return cb(Base.DEFAULT_MISSING_QUERY_MESSAGE_ + 'findOne.', null);
  }
  var columns = this.getColumns();
  var where = this.getQueryObject(this.resource) || Base.DEFAULT_WHERE_VALUE_;
  this.select(query, columns, where, function(err, results) {
    return cb(err, results ? results[0] : null);
  });
};

/**
 * Checks to see if a record exists, and attempts to create one if it does not.
 * The initial resource (used for `find` query) should be initialized before
 * invoking this method, and the supplied resource should be passed as the first
 * param.
 * @param {Object} resource The resource/record to create if one does not exist.
 * @param {Function(string, Object)} cb Callback function to fire when done.
 */
Base.prototype.findOrCreate = function(resource, cb) {
  this.findOne(function(err, result) {
    if (err || result) {
      cb(err, result);
    } else {
      this.resource = resource;
      this.insert(function(err, result) {
        err = err ? util.format(
            'There was an error creating the %s: %s',
            this.getTable() || 'record', err) : false;
        result = result || null;
        cb(err, result);
      });
    }
  }.bind(this));
};

/**
 * Inserts a record with the given parameters.
 * @param {Function} cb Callback function to fire when done.
 * @return {Function(string, Array)} Callback function.
 */
Base.prototype.insert = function(cb) {
  var self = this;
  var query = this.getQuery('insert');
  if (!query) {
    return cb(Base.DEFAULT_MISSING_QUERY_MESSAGE_ + 'insert.', null);
  }

  this.validate(function(err) {
    if (err) return cb(err, null);

    // Prepare the resource, adding any system generated values, like slug's.
    // The format it for inserting in DB.
    var resource = self.prepare();
    var insertObject = self.getQueryObject(resource) || {};

    this.db.getConnection(function(err, connection) {
      if (err) return cb(err, null);
      var q = connection.query(query, insertObject, function(err, result) {
        connection.release(); // Return this connection to the pool.
        if (err) {
          err = util.format('This %s could not be added: %s',
              self.getTable(), err);
          cb(err, null);
        } else {
          /**
           * During an insert the resource MUST be returned manually since the
           * Node-MySQL module does not return the inserted resource.
           */
          cb(err, resource);
        }
      });
      self.logQuery_(q);
    });
  });
};

/**
 * @param {Object} identifier The WHERE clause argument.
 * @param {Function} cb Callback function to fire when done.
 * @return {Function(string, Array)} Callback function.
 */
Base.prototype.update = function(identifier, cb) {
  var self = this;
  var query = this.getQuery('update');
  if (!query) {
    return cb(Base.DEFAULT_MISSING_QUERY_MESSAGE_ + ' update.', null);
  }

  this.validate(function(err) {
    if (err) return cb(err, null);

    // Prepare the resource, adding any system generated values, like slug's.
    // The format it for inserting in DB.
    var resource = self.prepare();
    var insertObject = self.getQueryObject(resource) || {};

    this.db.getConnection(function(err, connection) {
      if (err) return cb(err, null);

      var q = connection.query(
          query, [insertObject, identifier], function(err, result) {
            connection.release(); // Return this connection to the pool.
            if (err) {
              cb('This ' + self.getTable() + ' could not be updated: ' +
                 err, null);
            } else {
              cb(err, resource);
            }
          });
      self.logQuery_(q);
    });
  });
};

/**
 * Removes the resource identified by the parameters.
 * @param {Functon(<string>, <Array>)} cb Callback function to perform when
 *     done.
 */
Base.prototype.remove = function(cb) {
  var self = this;
  this.db.getConnection(function(err, connection) {
    if (err) return cb(err, null);
    var query = self.getQuery('remove');
    if (!query) {
      return cb(Base.DEFAULT_MISSING_QUERY_MESSAGE_ + ' remove.', null);
    }
    var where = self.getQueryObject(self.resource);
    var q = connection.query(query, where, function(err) {
      if (err) return cb(err, null);
      connection.release(); // Return this connection to the pool.
      if (err) {
        cb('This ' + self.getTable() + ' could not be deleted: ' + err, null);
      } else {
        cb(err);
      }
    });
    self.logQuery_(q);
  });
};

/**
 * Wrapper for SELECT statements.
 * Performs query and returns connection back to pool.
 * @param {string} query The query string to append values to.
 * @param {Object} columns The columns to retrieve in the query.
 * @param {Object} where The parameters that identify the result set.
 * @param {Functon(<string>, <Array>)} cb Callback function to perform when
 *     done.
 */
Base.prototype.select = function(query, columns, where, cb) {
  var self = this;
  this.db.getConnection(function(err, connection) {
    if (err) return cb(err, null);
    // Nesting tables allows for results like:
    //   {
    //     post: {id: '...', title: '...'},
    //     user: {id: '...', displayName: '...'}
    //   }
    var options = {sql: query, nestTables: true};
    var q = connection.query(options, [columns, where], function(err, results) {
      if (err) return cb(err, null);
      connection.release();
      cb(err, results || []);
    });
    self.logQuery_(q);
  });
};

/**
 * Validates the resource against the model's STRUCTURE.
 * @param {Functon(<Array>)} cb Callback function to perform when done.
 */
Base.prototype.validate = function(cb) {
  var resource = this.resource;
  var structure = this.getStructure();
  var errors = [];

  // TODO: Could be a MAP...
  if (structure) {
    for (var property in structure) {
      var rules = structure[property];

      // Validate Required Properties...
      if (rules['required'] && !resource[property]) {
        errors.push('The following required field is missing: ' +
            property);
      }

      // TODO: Validate Length (MIN and MAX)
      // TODO: Validate Types... (String, Number, Date, etc)...
    }
  }

  cb(errors.length ? errors : []);
};

/**
 * Converts the model resource into a query object with key:value pairs.
 * @return {?Object || null} The formatted resource.
 */
Base.prototype.getQueryObject = function() {
  if (!this.resource || !Object.keys(this.resource).length) {
    return null;
  }

  var structure = this.getStructure();
  var tableName = this.getTable();
  var resource = this.resource;
  var object = {};

  var fields = Object.keys(structure) || [];
  fields.forEach(function(field) {
    if (resource[field]) {
      object[tableName + '.' + field] = resource[field];
    }
  });

  return object;
};

/**
 * Logs the assembled and escaped query after it has run.
 * Application must set `LOG QUERIES` for the logs to be displayed.
 * @param {Object} query Node-Mysql query result.
 * @private
 */
Base.prototype.logQuery_ = function(query) {
  if (this.app.get('LOG QUERIES')) {
    query = query || {};
    var message = util.format('MySQL Query:\t %s', query.sql || 'N/A');
    console.log(message);
  }
};
<|endoftext|>


<commit_before>
var config = require('./config');

exports.InvitacionSlack = function(correo){

    var request = require('request');

    var options = {
        method: 'get',
        url: 'https://pgramadores.slack.com/api/users.admin.invite?token='+config.tokenSlack+'&email='+correo+'&resend=true',
        headers: {
            'Content-Type' : 'application/json'
        }
    }

    request(options, function (err, res, body) {
        if (err) {
            console.log('Error :', err);
        }else{
            console.log({okSlack:true});
        }
    });
}

exports.CorreoVerificacion = function(correo){

    var nodemailer = require('nodemailer');
    var smtpTransport = require('nodemailer-smtp-transport');

    var transporter = nodemailer.createTransport(smtpTransport({
        service: config.correo.servicio,
        auth: {
            user: config.correo.usuario,
            pass: config.correo.pass
        }
    }));

    //Generador de link de confirmación
    const crypto = require('crypto');
    const cipher = crypto.createCipher(config.cipher.metodo, config.cipher.pass);

    let encrypted = cipher.update(correo, config.cipher.input, config.cipher.output);
    encrypted += cipher.final(config.cipher.output);

    //Template de correo
    let CorreoHTML = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><meta name="viewport" content="width=device-width" /><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>confirmación suscripción</title>

confirmación suscripción

Hola Pro-Gramador/a

Hemos recibido una solicitud de suscripción desde este mail y queriamos confirmar que efectivamente eres tu quien se esta suscribiendo.

Para completar la suscripción te solicitamos hacer clic en el link que adjuntamos o copiar y pegar en tu navegador la url que esta mas abajo.

Apenas confirmes tu suscripción comenzaras a recibir nuestras novedades, articulos de interes del mundo de la informatica y las fechas de nuestros eventos gratuitos, asi que esta atento a tu correo.

haz clic aca para confirmar tu suscripción

ó copia y pega en tu navegador este link

${config.domain}/#!?AceptaSuscripcion=${encrypted}

No te olvides seguirnos en:

GithubFacebookTwitterYoutube

Contactanos:

Correo:contacto@pro-gramadores.org

Terminos y condiciones | <unsubscribe>Cancelar suscripción</unsubscribe>

`;

    //Configuración de correo
    let mailOptions = {
        from: '"Pro-Gramadores" <no-reply@pro-gramadores.org>',
        to: correo,
        subject: 'Confirmación de suscrpción a la comunidad de Pro-Gramadores',
        html: CorreoHTML
    };

    //Envio de correo
    transporter.sendMail(mailOptions, function(error, info){
        if(error){
            return console.log(error);
        }else {
            return console.log({okMail:true});
        }
    });
}

exports.DesencriptadorCorreo = function(codigo){

    const crypto = require('crypto');
    const decipher = crypto.createDecipher(config.cipher.metodo, config.cipher.pass);

    let correo = decipher.update(codigo, config.cipher.output, config.cipher.input);
    correo += decipher.final(config.cipher.input);
    return correo;
}

exports.Sanar = function(texto){

    var sanitizeHtml = require('sanitize-html');
    var xss = require('xss');

    //Si el texto es seguro retorna true, sino false
    return xss(sanitizeHtml(texto)) === texto ? true : false;
}

exports.UbicacionPorIp = function(clientIp){

    var geoip = require('geoip-lite');

    return geoip.lookup(clientIp);

}

exports.IP = function(req){

    var requestIp = require('request-ip');

    return requestIp.getClientIp(req);
}

exports.Ahora = function(){

    var moment = require('moment');

    return moment().format();
}
<commit_msg>se arreglo error fatal falta una i<commit_after>
var config = require('./config');

exports.InvitacionSlack = function(correo){

    var request = require('request');

    var options = {
        method: 'get',
        url: 'https://pgramadores.slack.com/api/users.admin.invite?token='+config.tokenSlack+'&email='+correo+'&resend=true',
        headers: {
            'Content-Type' : 'application/json'
        }
    }

    request(options, function (err, res, body) {
        if (err) {
            console.log('Error :', err);
        }else{
            console.log({okSlack:true});
        }
    });
}

exports.CorreoVerificacion = function(correo){

    var nodemailer = require('nodemailer');
    var smtpTransport = require('nodemailer-smtp-transport');

    var transporter = nodemailer.createTransport(smtpTransport({
        service: config.correo.servicio,
        auth: {
            user: config.correo.usuario,
            pass: config.correo.pass
        }
    }));

    //Generador de link de confirmación
    const crypto = require('crypto');
    const cipher = crypto.createCipher(config.cipher.metodo, config.cipher.pass);

    let encrypted = cipher.update(correo, config.cipher.input, config.cipher.output);
    encrypted += cipher.final(config.cipher.output);

    //Template de correo
    let CorreoHTML = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><meta name="viewport" content="width=device-width" /><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>confirmación suscripción</title>

confirmación suscripción

Hola Pro-Gramador/a

Hemos recibido una solicitud de suscripción desde este mail y queriamos confirmar que efectivamente eres tu quien se esta suscribiendo.

Para completar la suscripción te solicitamos hacer clic en el link que adjuntamos o copiar y pegar en tu navegador la url que esta mas abajo.

Apenas confirmes tu suscripción comenzaras a recibir nuestras novedades, articulos de interes del mundo de la informatica y las fechas de nuestros eventos gratuitos, asi que esta atento a tu correo.

haz clic aca para confirmar tu suscripción

ó copia y pega en tu navegador este link

${config.domain}/#!?AceptaSuscripcion=${encrypted}

No te olvides seguirnos en:

GithubFacebookTwitterYoutube

Contactanos:

Correo:contacto@pro-gramadores.org

Terminos y condiciones | <unsubscribe>Cancelar suscripción</unsubscribe>

`;

    //Configuración de correo
    let mailOptions = {
        from: '"Pro-Gramadores" <no-reply@pro-gramadores.org>',
        to: correo,
        subject: 'Confirmación de suscripción a la comunidad de Pro-Gramadores',
        html: CorreoHTML
    };

    //Envio de correo
    transporter.sendMail(mailOptions, function(error, info){
        if(error){
            return console.log(error);
        }else {
            return console.log({okMail:true});
        }
    });
}

exports.DesencriptadorCorreo = function(codigo){

    const crypto = require('crypto');
    const decipher = crypto.createDecipher(config.cipher.metodo, config.cipher.pass);

    let correo = decipher.update(codigo, config.cipher.output, config.cipher.input);
    correo += decipher.final(config.cipher.input);
    return correo;
}

exports.Sanar = function(texto){

    var sanitizeHtml = require('sanitize-html');
    var xss = require('xss');

    //Si el texto es seguro retorna true, sino false
    return xss(sanitizeHtml(texto)) === texto ? true : false;
}

exports.UbicacionPorIp = function(clientIp){

    var geoip = require('geoip-lite');

    return geoip.lookup(clientIp);

}

exports.IP = function(req){

    var requestIp = require('request-ip');

    return requestIp.getClientIp(req);
}

exports.Ahora = function(){

    var moment = require('moment');

    return moment().format();
}
<|endoftext|>


<commit_before>import CanvasView from 'demoPage/views/CanvasView';

export default () => {
    // 1. Get some data
    const dataArray = [];
    for (let i = 0; i < 15; i++) {
        dataArray.push({
            textCell: `Текст Яч. ${i}`,
            aliasCell: `Alias_Cell_${i}`,
            numberCell: i + 1,
            dateTimeCell: '2015-07-24T08:13:13.847Z',
            durationCell: 'P12DT5H42M',
            booleanCell: i % 2,
            userCell: [{ id: 'user.1', columns: ['J. J.'] }],
            referenceCell: [{ id: 'task.1', name: 'Ref 1', abbreviation: 'AB' }, { id: 'task.2', name: 'Ref 2' }, { id: 'task.3', name: 'Ref 3' }, { id: 'task.4', name: 'Ref 4' }, { id: 'task.5', name: 'Ref 5' }, { id: 'task.6', name: 'Ref 6' }, { id: 'task.7', name: 'Ref 7' }],
            enumCell: { valueExplained: ['123'] },
            documentCell: [
                {
                    id: `document.${i}`,
                    name: `Document ${i}`,
                    url: `GetDocument/${i}`
                }
            ]
        });
    }

    // 2. Create columns
    const columns = [
        {
            key: 'textCell',
            type: 'Text',
            dataType: 'String',
            title: 'TextCell',
            required: true,
            sorting: 'asc',
            editable: true,
            helpText: 'Text cell'
            // autocommit: true //property autocommit:true will be set for transliteratedFields
        },
        {
            key: 'aliasCell',
            type: 'Text',
            dataType: 'String',
            title: 'AliasCell',
            required: true,
            sorting: 'asc',
            editable: true,
            // autocommit: true //property autocommit:true will be set for transliteratedFields
            getReadonly: model => model.get('booleanCell')
        },
        {
            key: 'numberCell',
            type: 'Number',
            dataType: 'Integer',
            title: 'Number Cell',
            editable: true,
            autocommit: true
        },
        {
            key: 'dateTimeCell',
            type: 'DateTime',
            simplified: true,
            dataType: 'DateTime',
            title: 'DateTime Cell',
            editable: true,
            autocommit: true
        },
        {
            key: 'durationCell',
            type: 'Duration',
            dataType: 'Duration',
            title: 'Duration Cell',
            editable: true,
            autocommit: true
        },
        {
            key: 'booleanCell',
            type: 'Boolean',
            dataType: 'Boolean',
            title: 'Boolean Cell',
            editable: true,
            autocommit: true,
            getHidden: model => !model.get('numberCell') % 2 && !model.get('numberCell') % 3
        },
        {
            key: 'documentCell',
            type: 'Document',
            dataType: 'Document',
            title: 'Document',
            simplified: true,
            editable: true,
            autocommit: true
        },
        {
            key: 'referenceCell',
            type: 'Datalist',
            dataType: 'Instance',
            title: 'Reference Cell',
            simplified: true,
            required: true,
            customClass: 'dropdown_root',
            controller: new Core.form.editors.reference.controllers.DemoReferenceEditorController(),
            editable: true,
            showCheckboxes: true,
            autocommit: true,
            maxQuantitySelected: 5,
            getReadonly: model => model.get('numberCell') % 2
        }
    ];

    const collection = new Backbone.Collection(dataArray);

    // 3. Create grid
    const gridController = new Core.list.controllers.GridController({
        columns,
        transliteratedFields: {
            textCell: 'aliasCell'
        },
        selectableBehavior: 'multi',
        showToolbar: true,
        showSearch: true,
        showCheckbox: true,
        showRowIndex: true,
        collection,
        title: 'Editable grid'
    });

    const handleAction = (action, items) => {
        switch (action.id) {
            case 'add':
                collection.add({
                    textCell: 'New item'
                });
                break;
            case 'delete':
                collection.remove(items);
                break;
            default:
                break;
        }
    };

    gridController.on('execute', handleAction);

    // 4. Show created views
    return new CanvasView({
        view: gridController.view,
        canvas: {
            height: '250px',
            width: '400px'
        },
        region: {
            float: 'left'
        }
    });
};
<commit_msg>Simplify complex grid.<commit_after>import CanvasView from 'demoPage/views/CanvasView';

export default () => {
    // 1. Get some data
    const dataArray = [];
    for (let i = 0; i < 15; i++) {
        dataArray.push({
            textCell: `Текст Яч. ${i}`,
            aliasCell: `Alias_Cell_${i}`,
            numberCell: i + 1,
            dateTimeCell: '2015-07-24T08:13:13.847Z',
            durationCell: 'P12DT5H42M',
            booleanCell: i % 2,
            userCell: [{ id: 'user.1', columns: ['J. J.'] }],
            referenceCell: [{ id: 'task.1', name: 'Ref 1', abbreviation: 'AB' }, { id: 'task.2', name: 'Ref 2' }, { id: 'task.3', name: 'Ref 3' }, { id: 'task.4', name: 'Ref 4' }, { id: 'task.5', name: 'Ref 5' }, { id: 'task.6', name: 'Ref 6' }, { id: 'task.7', name: 'Ref 7' }],
            enumCell: { valueExplained: ['123'] },
            documentCell: [
                {
                    id: `document.${i}`,
                    name: `Document ${i}`,
                    url: `GetDocument/${i}`
                }
            ]
        });
    }

    // 2. Create columns
    const columns = [
        {
            key: 'textCell',
            type: 'Text',
            dataType: 'String',
            title: 'TextCell',
            required: true,
            sorting: 'asc',
            editable: true,
            helpText: 'Text cell'
            // autocommit: true //property autocommit:true will be set for transliteratedFields
        },
        {
            key: 'textCell',
            type: 'TextArea',
            dataType: 'String',
            title: 'TextCell',
            required: true,
            sorting: 'asc',
            editable: true,
            helpText: 'Text cell'
            // autocommit: true //property autocommit:true will be set for transliteratedFields
        },
        {
            key: 'textCell',
            type: 'Text',
            dataType: 'String',
            title: 'TextCell',
            required: true,
            sorting: 'asc',
            editable: true,
            helpText: 'Text cell'
            // autocommit: true //property autocommit:true will be set for transliteratedFields
        },
        {
            key: 'aliasCell',
            type: 'Text',
            dataType: 'String',
            title: 'AliasCell',
            required: true,
            sorting: 'asc',
            editable: true,
            // autocommit: true //property autocommit:true will be set for transliteratedFields
            getReadonly: model => model.get('booleanCell')
        },
        {
            key: 'numberCell',
            type: 'Number',
            dataType: 'Integer',
            title: 'Number Cell',
            editable: true,
            autocommit: true
        },
        {
            key: 'dateTimeCell',
            type: 'DateTime',
            simplified: true,
            dataType: 'DateTime',
            title: 'DateTime Cell',
            editable: true,
            autocommit: true
        },
        {
            key: 'durationCell',
            type: 'Duration',
            dataType: 'Duration',
            title: 'Duration Cell',
            editable: true,
            autocommit: true
        },
        {
            key: 'booleanCell',
            type: 'Boolean',
            dataType: 'Boolean',
            title: 'Boolean Cell',
            editable: true,
            autocommit: true,
            getHidden: model => !model.get('numberCell') % 2 && !model.get('numberCell') % 3
        },
        {
            key: 'documentCell',
            type: 'Document',
            dataType: 'Document',
            title: 'Document',
            editable: true,
            autocommit: true
        },
        {
            key: 'referenceCell',
            type: 'Datalist',
            dataType: 'Instance',
            title: 'Reference Cell',
            required: true,
            customClass: 'dropdown_root',
            controller: new Core.form.editors.reference.controllers.DemoReferenceEditorController(),
            editable: true,
            showCheckboxes: true,
            autocommit: true,
            maxQuantitySelected: 5,
            getReadonly: model => model.get('numberCell') % 2
        }
    ];

    const collection = new Backbone.Collection(dataArray);

    // 3. Create grid
    const gridController = new Core.list.controllers.GridController({
        columns,
        transliteratedFields: {
            textCell: 'aliasCell'
        },
        selectableBehavior: 'multi',
        showToolbar: true,
        showSearch: true,
        showCheckbox: true,
        showRowIndex: true,
        collection,
        title: 'Editable grid'
    });

    const handleAction = (action, items) => {
        switch (action.id) {
            case 'add':
                collection.add({
                    textCell: 'New item'
                });
                break;
            case 'delete':
                collection.remove(items);
                break;
            default:
                break;
        }
    };

    gridController.on('execute', handleAction);

    // 4. Show created views
    return new CanvasView({
        view: gridController.view,
        canvas: {
            height: '250px',
            width: '400px'
        },
        region: {
            float: 'left'
        }
    });
};
<|endoftext|>


<commit_before>$(document).ready(function() {
  $('img[src$="https://cdn1.readmore.de/img/themes/readmore/side_left_setup2.png"]').replaceWith('');
  $('img[src$="https://cdn1.readmore.de/img/themes/readmore/icon_plus.jpg"]').replaceWith('');
  $('img[src$="https://cdn1.readmore.de/img/themes/readmore/icon_minus.jpg"]').replaceWith('');
  $('img[src$="https://cdn1.readmore.de/img/themes/readmore/arrow_last_item.gif"]').replaceWith('');
  $('img[src$="https://cdn1.readmore.de/img/themes/readmore/arrow_last_item2.gif"]').replaceWith('');
});
<commit_msg>replace icon images with font awesome icons<commit_after>$(document).ready(function() {
  $('img[src$="https://cdn1.readmore.de/img/themes/readmore/side_left_setup2.png"]').replaceWith('');
  $('img[src$="https://cdn1.readmore.de/img/themes/readmore/icon_plus.jpg"]').replaceWith('');
  $('img[src$="https://cdn1.readmore.de/img/themes/readmore/icon_minus.jpg"]').replaceWith('');
  $('img[src$="https://cdn1.readmore.de/img/themes/readmore/arrow_last_item.gif"]').replaceWith('');
  $('img[src$="https://cdn1.readmore.de/img/themes/readmore/arrow_last_item2.gif"]').replaceWith('');

  var forumButtons = $('.controls li input').get(0).outerHTML.replace(/^<input/, "<button");
  $('.controls li input').replaceWith(forumButtons);

  $('.controls li:nth-child(1) button').append('');
  $('.controls li:nth-child(2) button').append('');
  $('.controls li:nth-child(3) button').append('');
  $('.controls li:nth-child(4) button').append('');
  $('.controls li:nth-child(5) button').append('');
  $('.controls li:nth-child(6) button').append('');
  $('.controls li:nth-child(7) button').append('');
  $('.controls li:nth-child(8) button').append('');
  $('.controls li:nth-child(9) button').append('');
  $('.controls li:nth-child(10) button').append('');

});
<|endoftext|>


<commit_before>'use strict';

const log = require('intel');
const { Type } = require('selenium-webdriver').logging;
const harBuilder = require('../../support/harBuilder');
const perflogParser = require('chrome-har');
const traceCategoriesParser = require('../../support/traceCategoriesParser');

const CHROME_NAME_AND_VERSION_JS = `return (function() {
  var match = navigator.userAgent.match(/(Chrom(e|ium))\\/(([0-9]+\\.?)*)/);

  if (match)
    return {
      'name': match[1],
      'version': match[3]
    };
  else
    return {};
})();`;

const PAGE_TITLE_JS = 'return document.title;';

class ChromeDelegate {
  constructor({ skipHar = false, chrome = {} }) {
    this.skipHar = skipHar;
    this.logPerfEntries = !!chrome.collectPerfLog;
    this.collectTracingEvents = !!chrome.collectTracingEvents;
    this.chrome = chrome;
  }

  async onStartRun() {
    this.hars = [];
  }

  async onStartIteration(runner) {
    if (this.skipHar) {
      return;
    }

    // remove irrelevant entries from performance log
    // and since Chromedriver 2.29 there's a bug
    // https://bugs.chromium.org/p/chromedriver/issues/detail?id=1811
    // that can be fixed by emptying the logs twice :|
    let logs;
    do {
      logs = await runner.getLogs(Type.PERFORMANCE);
    } while (logs.length > 0);
  }

  async onStopIteration(runner, index, results) {
    if (this.skipHar) {
      return;
    }

    log.debug('Getting performance logs from Chrome');

    const logs = await runner.getLogs(Type.PERFORMANCE);

    const messages = logs.map(entry => JSON.parse(entry.message).message);

    if (this.logPerfEntries) {
      results.extraJson[`chromePerflog-${index}.json`] = messages;
    }
    if (this.collectTracingEvents) {
      const trace = traceCategoriesParser.parse(messages);
      results.extraJson[`trace-${index}.json`] = trace;
    }

    const har = perflogParser.harFromMessages(messages);
    const info = await runner.runScript(
      CHROME_NAME_AND_VERSION_JS,
      'CHROME_NAME_AND_VERSION_JS'
    );
    if (this.chrome.mobileEmulation) {
      info.name = `Chrome Emulated ${this.chrome.mobileEmulation.deviceName}`;
    }
    harBuilder.addBrowser(har, info.name, info.version);

    if (har.log.pages.length > 0) {
      const title = await runner.runScript(PAGE_TITLE_JS, 'PAGE_TITLE_JS');
      har.log.pages[0].title = `${title} run ${index + 1}`;
    }

    this.hars.push(har);
  }

  async onStopRun(result) {
    result.har = harBuilder.mergeHars(this.hars);
  }
}

module.exports = ChromeDelegate;
<commit_msg>Collect the log exactly twice see #420 (#422)<commit_after>'use strict';

const log = require('intel');
const { Type } = require('selenium-webdriver').logging;
const harBuilder = require('../../support/harBuilder');
const perflogParser = require('chrome-har');
const traceCategoriesParser = require('../../support/traceCategoriesParser');

const CHROME_NAME_AND_VERSION_JS = `return (function() {
  var match = navigator.userAgent.match(/(Chrom(e|ium))\\/(([0-9]+\\.?)*)/);

  if (match)
    return {
      'name': match[1],
      'version': match[3]
    };
  else
    return {};
})();`;

const PAGE_TITLE_JS = 'return document.title;';

class ChromeDelegate {
  constructor({ skipHar = false, chrome = {} }) {
    this.skipHar = skipHar;
    this.logPerfEntries = !!chrome.collectPerfLog;
    this.collectTracingEvents = !!chrome.collectTracingEvents;
    this.chrome = chrome;
  }

  async onStartRun() {
    this.hars = [];
  }

  async onStartIteration(runner) {
    if (this.skipHar) {
      return;
    }

    // remove irrelevant entries from performance log
    // and since Chromedriver 2.29 there's a bug
    // https://bugs.chromium.org/p/chromedriver/issues/detail?id=1811
    // that can be fixed by emptying the logs twice :|
    await runner.getLogs(Type.PERFORMANCE);
    await runner.getLogs(Type.PERFORMANCE);
  }

  async onStopIteration(runner, index, results) {
    if (this.skipHar) {
      return;
    }

    log.debug('Getting performance logs from Chrome');

    const logs = await runner.getLogs(Type.PERFORMANCE);

    const messages = logs.map(entry => JSON.parse(entry.message).message);

    if (this.logPerfEntries) {
      results.extraJson[`chromePerflog-${index}.json`] = messages;
    }
    if (this.collectTracingEvents) {
      const trace = traceCategoriesParser.parse(messages);
      results.extraJson[`trace-${index}.json`] = trace;
    }

    const har = perflogParser.harFromMessages(messages);
    const info = await runner.runScript(
      CHROME_NAME_AND_VERSION_JS,
      'CHROME_NAME_AND_VERSION_JS'
    );
    if (this.chrome.mobileEmulation) {
      info.name = `Chrome Emulated ${this.chrome.mobileEmulation.deviceName}`;
    }
    harBuilder.addBrowser(har, info.name, info.version);

    if (har.log.pages.length > 0) {
      const title = await runner.runScript(PAGE_TITLE_JS, 'PAGE_TITLE_JS');
      har.log.pages[0].title = `${title} run ${index + 1}`;
    }

    this.hars.push(har);
  }

  async onStopRun(result) {
    result.har = harBuilder.mergeHars(this.hars);
  }
}

module.exports = ChromeDelegate;
<|endoftext|>


<commit_before>moduleAid.VERSION = '1.0.1';

this._getFindBarHidden = function() { return linkedPanel._findBarHidden; };

this.reopenPerTabSelected = function() {
	if(!linkedPanel._findBarHidden) {
		gFindBar.open();
	} else {
		gFindBar.close();
	}
};

this.perTabOnOpen = function() {
	if(gFindBar._findMode != gFindBar.FIND_TYPEAHEAD) {
		linkedPanel._findBarHidden = true;
	}
};

this.perTabOnClose = function() {
	linkedPanel._findBarHidden = false;
};

moduleAid.LOADMODULE = function() {
	listenerAid.add(gBrowser.tabContainer, "TabSelect", reopenPerTabSelected);
	listenerAid.add(window, 'OpenedFindBar', perTabOnOpen);
	listenerAid.add(window, 'ClosedFindBar', perTabOnClose);

	if(!gFindBar.hidden) {
		linkedPanel._findBarHidden = true;
	}
};

moduleAid.UNLOADMODULE = function() {
	// Clean up everything this module may have added to tabs and panels and documents
	for(var t=0; t<gBrowser.mTabs.length; t++) {
		delete $(gBrowser.mTabs[t].linkedPanel)._findBarHidden;
	}

	listenerAid.remove(gBrowser.tabContainer, "TabSelect", reopenPerTabSelected);
	listenerAid.remove(window, 'OpenedFindBar', perTabOnOpen);
	listenerAid.remove(window, 'ClosedFindBar', perTabOnClose);

	// Have to set this back
	_getFindBarHidden = function() { return gFindBar.hidden; };
};
<commit_msg>bugfix from FF25 compatibility changes<commit_after>moduleAid.VERSION = '1.0.2';

this._getFindBarHidden = function() { return linkedPanel._findBarOpen; };

this.reopenPerTabSelected = function() {
	if(linkedPanel._findBarOpen) {
		gFindBar.open();
	} else {
		gFindBar.close();
	}
};

this.perTabOnOpen = function() {
	if(gFindBar._findMode != gFindBar.FIND_TYPEAHEAD) {
		linkedPanel._findBarOpen = true;
	}
};

this.perTabOnClose = function() {
	linkedPanel._findBarOpen = false;
};

moduleAid.LOADMODULE = function() {
	listenerAid.add(gBrowser.tabContainer, "TabSelect", reopenPerTabSelected);
	listenerAid.add(window, 'OpenedFindBar', perTabOnOpen);
	listenerAid.add(window, 'ClosedFindBar', perTabOnClose);

	if(!gFindBar.hidden) {
		linkedPanel._findBarOpen = true;
	}
};

moduleAid.UNLOADMODULE = function() {
	// Clean up everything this module may have added to tabs and panels and documents
	for(var t=0; t<gBrowser.mTabs.length; t++) {
		delete $(gBrowser.mTabs[t].linkedPanel)._findBarOpen;
	}

	listenerAid.remove(gBrowser.tabContainer, "TabSelect", reopenPerTabSelected);
	listenerAid.remove(window, 'OpenedFindBar', perTabOnOpen);
	listenerAid.remove(window, 'ClosedFindBar', perTabOnClose);

	// Have to set this back
	_getFindBarHidden = function() { return gFindBar.hidden; };
};
<|endoftext|>