<commit_before>'use strict'

const ipcRenderer = require('electron').ipcRenderer
const remote = require('electron').remote

// Helper function to resolve relative url.
var a = window.top.document.createElement('a')
var resolveURL = function (url) {
  a.href = url
  return a.href
}

// Window object returned by "window.open".
var BrowserWindowProxy = (function () {
  BrowserWindowProxy.proxies = {}

  BrowserWindowProxy.getOrCreate = function (guestId) {
    var base
    return (base = this.proxies)[guestId] != null ? base[guestId] : base[guestId] = new BrowserWindowProxy(guestId)
  }

  BrowserWindowProxy.remove = function (guestId) {
    return delete this.proxies[guestId]
  }

  function BrowserWindowProxy (guestId1) {
    this.guestId = guestId1
    this.closed = false
    ipcRenderer.once('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + this.guestId, () => {
      BrowserWindowProxy.remove(this.guestId)
      this.closed = true
    })
  }

  BrowserWindowProxy.prototype.close = function () {
    return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', this.guestId)
  }

  BrowserWindowProxy.prototype.focus = function () {
    return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'focus')
  }

  BrowserWindowProxy.prototype.blur = function () {
    return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'blur')
  }

  Object.defineProperty(BrowserWindowProxy.prototype, 'location', {
    get: function () {
      return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'getURL')
    },
    set: function (url) {
      return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'loadURL', url)
    }
  })

  BrowserWindowProxy.prototype.postMessage = function (message, targetOrigin) {
    if (targetOrigin == null) {
      targetOrigin = '*'
    }
    return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', this.guestId, message, targetOrigin, window.location.origin)
  }

  BrowserWindowProxy.prototype['eval'] = function (...args) {
    return ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'executeJavaScript'].concat(args))
  }

  return BrowserWindowProxy
})()

if (process.guestInstanceId == null) {
  // Override default window.close.
  window.close = function () {
    return remote.getCurrentWindow().close()
  }
}

// Make the browser window or guest view emit "new-window" event.
window.open = function (url, frameName, features) {
  var feature, guestId, i, j, len, len1, name, options, ref1, ref2, value
  if (frameName == null) {
    frameName = ''
  }
  if (features == null) {
    features = ''
  }
  options = {}

  // TODO remove hyphenated options in both of the following arrays for 1.0
  const ints = ['x', 'y', 'width', 'height', 'min-width', 'minWidth', 'max-width', 'maxWidth', 'min-height', 'minHeight', 'max-height', 'maxHeight', 'zoom-factor', 'zoomFactor']
  const webPreferences = ['zoom-factor', 'zoomFactor', 'node-integration', 'nodeIntegration', 'preload']
  const disposition = 'new-window'

  // Make sure to get rid of excessive whitespace in the property name
  ref1 = features.split(/,\s*/)
  for (i = 0, len = ref1.length; i < len; i++) {
    feature = ref1[i]
    ref2 = feature.split(/\s*=/)
    name = ref2[0]
    value = ref2[1]
    value = value === 'yes' || value === '1' ? true : value === 'no' || value === '0' ? false : value
    if (webPreferences.includes(name)) {
      if (options.webPreferences == null) {
        options.webPreferences = {}
      }
      options.webPreferences[name] = value
    } else {
      options[name] = value
    }
  }
  if (options.left) {
    if (options.x == null) {
      options.x = options.left
    }
  }
  if (options.top) {
    if (options.y == null) {
      options.y = options.top
    }
  }
  if (options.title == null) {
    options.title = frameName
  }
  if (options.width == null) {
    options.width = 800
  }
  if (options.height == null) {
    options.height = 600
  }

  // Resolve relative urls.
  url = resolveURL(url)
  for (j = 0, len1 = ints.length; j < len1; j++) {
    name = ints[j]
    if (options[name] != null) {
      options[name] = parseInt(options[name], 10)
    }
  }
  guestId = ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, disposition, options)
  if (guestId) {
    return BrowserWindowProxy.getOrCreate(guestId)
  } else {
    return null
  }
}

// Use the dialog API to implement alert().
window.alert = function (message, title) {
  var buttons
  if (arguments.length === 0) {
    message = ''
  }
  if (title == null) {
    title = ''
  }
  buttons = ['OK']
  message = String(message)
  remote.dialog.showMessageBox(remote.getCurrentWindow(), {
    message: message,
    title: title,
    buttons: buttons
  })
}

// And the confirm().
window.confirm = function (message, title) {
  var buttons, cancelId
  if (title == null) {
    title = ''
  }
  buttons = ['OK', 'Cancel']
  cancelId = 1
  return !remote.dialog.showMessageBox(remote.getCurrentWindow(), {
    message: message,
    title: title,
    buttons: buttons,
    cancelId: cancelId
  })
}

// But we do not support prompt().
window.prompt = function () {
  throw new Error('prompt() is and will not be supported.')
}

if (process.openerId != null) {
  window.opener = BrowserWindowProxy.getOrCreate(process.openerId)
}

ipcRenderer.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, message, sourceOrigin) {
  // Manually dispatch event instead of using postMessage because we also need to
  // set event.source.
  event = document.createEvent('Event')
  event.initEvent('message', false, false)
  event.data = message
  event.origin = sourceOrigin
  event.source = BrowserWindowProxy.getOrCreate(sourceId)
  return window.dispatchEvent(event)
})

// Forward history operations to browser.
var sendHistoryOperation = function (...args) {
  return ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_NAVIGATION_CONTROLLER'].concat(args))
}

var getHistoryOperation = function (...args) {
  return ipcRenderer.sendSync.apply(ipcRenderer, ['ELECTRON_SYNC_NAVIGATION_CONTROLLER'].concat(args))
}

window.history.back = function () {
  return sendHistoryOperation('goBack')
}

window.history.forward = function () {
  return sendHistoryOperation('goForward')
}

window.history.go = function (offset) {
  return sendHistoryOperation('goToOffset', offset)
}

Object.defineProperty(window.history, 'length', {
  get: function () {
    return getHistoryOperation('length')
  }
})

// The initial visibilityState.
let cachedVisibilityState = process.argv.includes('--hidden-page') ? 'hidden' : 'visible'

// Subscribe to visibilityState changes.
ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', function (event, visibilityState) {
  if (cachedVisibilityState !== visibilityState) {
    cachedVisibilityState = visibilityState
    document.dispatchEvent(new Event('visibilitychange'))
  }
})

// Make document.hidden and document.visibilityState return the correct value.
Object.defineProperty(document, 'hidden', {
  get: function () {
    return cachedVisibilityState !== 'visible'
  }
})

Object.defineProperty(document, 'visibilityState', {
  get: function () {
    return cachedVisibilityState
  }
})
<commit_msg>Remove hyphenated options<commit_after>'use strict'

const ipcRenderer = require('electron').ipcRenderer
const remote = require('electron').remote

// Helper function to resolve relative url.
var a = window.top.document.createElement('a')
var resolveURL = function (url) {
  a.href = url
  return a.href
}

// Window object returned by "window.open".
var BrowserWindowProxy = (function () {
  BrowserWindowProxy.proxies = {}

  BrowserWindowProxy.getOrCreate = function (guestId) {
    var base
    return (base = this.proxies)[guestId] != null ? base[guestId] : base[guestId] = new BrowserWindowProxy(guestId)
  }

  BrowserWindowProxy.remove = function (guestId) {
    return delete this.proxies[guestId]
  }

  function BrowserWindowProxy (guestId1) {
    this.guestId = guestId1
    this.closed = false
    ipcRenderer.once('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + this.guestId, () => {
      BrowserWindowProxy.remove(this.guestId)
      this.closed = true
    })
  }

  BrowserWindowProxy.prototype.close = function () {
    return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSE', this.guestId)
  }

  BrowserWindowProxy.prototype.focus = function () {
    return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'focus')
  }

  BrowserWindowProxy.prototype.blur = function () {
    return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'blur')
  }

  Object.defineProperty(BrowserWindowProxy.prototype, 'location', {
    get: function () {
      return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'getURL')
    },
    set: function (url) {
      return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'loadURL', url)
    }
  })

  BrowserWindowProxy.prototype.postMessage = function (message, targetOrigin) {
    if (targetOrigin == null) {
      targetOrigin = '*'
    }
    return ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', this.guestId, message, targetOrigin, window.location.origin)
  }

  BrowserWindowProxy.prototype['eval'] = function (...args) {
    return ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'executeJavaScript'].concat(args))
  }

  return BrowserWindowProxy
})()

if (process.guestInstanceId == null) {
  // Override default window.close.
  window.close = function () {
    return remote.getCurrentWindow().close()
  }
}

// Make the browser window or guest view emit "new-window" event.
window.open = function (url, frameName, features) {
  var feature, guestId, i, j, len, len1, name, options, ref1, ref2, value
  if (frameName == null) {
    frameName = ''
  }
  if (features == null) {
    features = ''
  }
  options = {}

  const ints = ['x', 'y', 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'zoomFactor']
  const webPreferences = ['zoomFactor', 'nodeIntegration', 'preload']
  const disposition = 'new-window'

  // Make sure to get rid of excessive whitespace in the property name
  ref1 = features.split(/,\s*/)
  for (i = 0, len = ref1.length; i < len; i++) {
    feature = ref1[i]
    ref2 = feature.split(/\s*=/)
    name = ref2[0]
    value = ref2[1]
    value = value === 'yes' || value === '1' ? true : value === 'no' || value === '0' ? false : value
    if (webPreferences.includes(name)) {
      if (options.webPreferences == null) {
        options.webPreferences = {}
      }
      options.webPreferences[name] = value
    } else {
      options[name] = value
    }
  }
  if (options.left) {
    if (options.x == null) {
      options.x = options.left
    }
  }
  if (options.top) {
    if (options.y == null) {
      options.y = options.top
    }
  }
  if (options.title == null) {
    options.title = frameName
  }
  if (options.width == null) {
    options.width = 800
  }
  if (options.height == null) {
    options.height = 600
  }

  // Resolve relative urls.
  url = resolveURL(url)
  for (j = 0, len1 = ints.length; j < len1; j++) {
    name = ints[j]
    if (options[name] != null) {
      options[name] = parseInt(options[name], 10)
    }
  }
  guestId = ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', url, frameName, disposition, options)
  if (guestId) {
    return BrowserWindowProxy.getOrCreate(guestId)
  } else {
    return null
  }
}

// Use the dialog API to implement alert().
window.alert = function (message, title) {
  var buttons
  if (arguments.length === 0) {
    message = ''
  }
  if (title == null) {
    title = ''
  }
  buttons = ['OK']
  message = String(message)
  remote.dialog.showMessageBox(remote.getCurrentWindow(), {
    message: message,
    title: title,
    buttons: buttons
  })
}

// And the confirm().
window.confirm = function (message, title) {
  var buttons, cancelId
  if (title == null) {
    title = ''
  }
  buttons = ['OK', 'Cancel']
  cancelId = 1
  return !remote.dialog.showMessageBox(remote.getCurrentWindow(), {
    message: message,
    title: title,
    buttons: buttons,
    cancelId: cancelId
  })
}

// But we do not support prompt().
window.prompt = function () {
  throw new Error('prompt() is and will not be supported.')
}

if (process.openerId != null) {
  window.opener = BrowserWindowProxy.getOrCreate(process.openerId)
}

ipcRenderer.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, message, sourceOrigin) {
  // Manually dispatch event instead of using postMessage because we also need to
  // set event.source.
  event = document.createEvent('Event')
  event.initEvent('message', false, false)
  event.data = message
  event.origin = sourceOrigin
  event.source = BrowserWindowProxy.getOrCreate(sourceId)
  return window.dispatchEvent(event)
})

// Forward history operations to browser.
var sendHistoryOperation = function (...args) {
  return ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_NAVIGATION_CONTROLLER'].concat(args))
}

var getHistoryOperation = function (...args) {
  return ipcRenderer.sendSync.apply(ipcRenderer, ['ELECTRON_SYNC_NAVIGATION_CONTROLLER'].concat(args))
}

window.history.back = function () {
  return sendHistoryOperation('goBack')
}

window.history.forward = function () {
  return sendHistoryOperation('goForward')
}

window.history.go = function (offset) {
  return sendHistoryOperation('goToOffset', offset)
}

Object.defineProperty(window.history, 'length', {
  get: function () {
    return getHistoryOperation('length')
  }
})

// The initial visibilityState.
let cachedVisibilityState = process.argv.includes('--hidden-page') ? 'hidden' : 'visible'

// Subscribe to visibilityState changes.
ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', function (event, visibilityState) {
  if (cachedVisibilityState !== visibilityState) {
    cachedVisibilityState = visibilityState
    document.dispatchEvent(new Event('visibilitychange'))
  }
})

// Make document.hidden and document.visibilityState return the correct value.
Object.defineProperty(document, 'hidden', {
  get: function () {
    return cachedVisibilityState !== 'visible'
  }
})

Object.defineProperty(document, 'visibilityState', {
  get: function () {
    return cachedVisibilityState
  }
})
<|endoftext|>


<commit_before>'use strict';

// Load modules

const Tty = require('tty');
const Diff = require('diff');
const StringifySafe = require('json-stringify-safe');

// Declare internals

const internals = {
    width: 50
};

exports = module.exports = internals.Reporter = function (options) {

    this.settings = options;
    this.count = 0;
    this.last = [];

    this.colors = internals.colors(options.colors);
};

internals.Reporter.prototype.start = function (notebook) {

};

internals.Reporter.prototype.test = function (test) {

    if (this.settings.progress === 0) {
        return;
    }

    if (this.settings.progress === 1) {

        // ..x....x.-..

        if (!this.count) {
            this.report('\n  ');
        }

        this.count++;

        if ((this.count - 1) % internals.width === 0) {
            this.report('\n  ');
        }

        this.report(test.err ? this.colors.red('x') : (test.skipped || test.todo ? this.colors.magenta('-') : '.'));
    }
    else {

        const check = process.platform === 'win32' ? '\u221A' : '\u2714';
        const asterisk = process.platform === 'win32' ? '\u00D7' : '\u2716';

        // Verbose (Spec reporter)

        for (let i = 0; i < test.path.length; ++i) {
            if (test.path[i] !== this.last[i]) {
                this.report(internals.spacer(i * 2) + test.path[i] + '\n');
            }
        }

        this.last = test.path;

        const spacer = internals.spacer(test.path.length * 2);
        if (test.err) {
            this.report(spacer + this.colors.red(asterisk + test.id + ') ' + test.relativeTitle) + '\n');
        }
        else {
            const symbol = test.skipped || test.todo ? this.colors.magenta('-') : this.colors.green(check);
            this.report(spacer + symbol + ' ' + this.colors.gray(test.id + ') ' + test.relativeTitle +
                ' (' + test.duration + ' ms)') + '\n');
        }
    }
};

internals.spacer = function (length) {

    return new Array(length + 1).join(' ');
};

internals.stringifyReplacer = function (key, value) {

    // Show usually invisible values from JSON.stringify in a different way,
    // follow the bracket format of json-stringify-safe.

    if (value === undefined) {
        return '[undefined]';
    }

    if (typeof value === 'function' || value === Infinity || value === -Infinity) {
        return '[' + value.toString() + ']';
    }

    /* $lab:coverage:off$ */ // There is no way to cover that in node 0.10
    if (typeof value === 'symbol') {
        return '[' + value.toString() + ']';
    }
    /* $lab:coverage:on$ */

    return value;
};

internals.Reporter.prototype.end = function (notebook) {

    if (this.settings.progress) {
        this.report('\n\n');
    }

    // Colors

    const red = this.colors.red;
    const green = this.colors.green;
    const gray = this.colors.gray;
    const yellow = this.colors.yellow;
    const whiteRedBg = this.colors.whiteRedBg;
    const blackGreenBg = this.colors.blackGreenBg;

    // Tests

    const failures = notebook.tests.filter(internals.filterFailures);

    const skipped = notebook.tests.filter(internals.filterSkipped);

    let output = '';
    const totalTests = notebook.tests.length - skipped.length;

    const errors = notebook.errors || [];
    if (errors.length) {
        output += 'Test script errors:\n\n';
        errors.forEach((err) => {

            output += red(err.message) + '\n';
            if (err.stack) {
                const stack = err.stack.slice(err.stack.indexOf('\n') + 1)
                                       .replace(/^/gm, '  ')
                                       .split('\n')
                                       .filter(internals.filterNodeModules)               // Remove node_modules files
                                       .slice(0, 5)                                       // Show only first 5 stack lines
                                       .join('\n');

                output += gray(stack) + '\n';
            }

            output += '\n';
        });
        output += red('There were ' + errors.length + ' test script error(s).') + '\n\n';
    }

    if (failures.length) {
        output += 'Failed tests:\n\n';

        for (let i = 0; i < failures.length; ++i) {
            const test = failures[i];
            const message = test.err.message || '';

            output += '  ' + test.id + ') ' + test.title + ':\n\n';

            // Actual vs Expected

            if (test.err.actual !== undefined &&
                test.err.expected !== undefined) {

                const actual = StringifySafe(test.err.actual, internals.stringifyReplacer, 2);
                const expected = StringifySafe(test.err.expected, internals.stringifyReplacer, 2);

                output += '      ' + whiteRedBg('actual') + ' ' + blackGreenBg('expected') + '\n\n      ';

                const comparison = Diff.diffWords(actual, expected);
                for (let j = 0; j < comparison.length; ++j) {
                    const item = comparison[j];
                    const value = item.value;
                    const lines = value.split('\n');
                    for (let k = 0; k < lines.length; ++k) {
                        if (k) {
                            output += '\n      ';
                        }

                        if (item.added || item.removed) {
                            output += item.added ? blackGreenBg(lines[k]) : whiteRedBg(lines[k]);
                        }
                        else {
                            output += lines[k];
                        }
                    }
                }

                output += '\n\n      ' + yellow(message);
                output += '\n\n';
            }
            else {
                output += '      ' + red(message) + '\n\n';
            }

            if (test.err.at) {
                output += gray('      at ' + test.err.at.filename + ':' + test.err.at.line + ':' + test.err.at.column) + '\n';
            }
            else if (!test.timeout &&
                test.err.stack) {

                output += gray(test.err.stack.slice(test.err.stack.indexOf('\n') + 1).replace(/^/gm, '  ')) + '\n';
            }

            if (test.err.data) {
                const isObject = typeof test.err.data === 'object' && !Array.isArray(test.err.data);
                let errorData = StringifySafe(test.err.data, null, isObject ? 4 : null);
                if (isObject) {
                    errorData = errorData.replace(/(\n\s*)"(.*)"\:/g, '$1$2:').split('\n').slice(1, -1).join('\n');
                }

                output += gray('\n      Additional error data:\n' + errorData.replace(/^/gm, '      ')) + '\n';
            }

            output += '\n';
        }

        output += '\n' + red(failures.length + ' of ' + totalTests + ' tests failed') + '\n';
    }
    else {
        output += green(totalTests + ' tests complete') + '\n';
    }

    output += 'Test duration: ' + notebook.ms + ' ms\n';

    // Assertions

    if (notebook.assertions !== undefined) {
        output += 'Assertions count: ' + notebook.assertions + ' (verbosity: ' + (notebook.assertions / totalTests).toFixed(2) + ')\n';
    }

    // Leaks

    if (notebook.leaks) {
        if (notebook.leaks.length) {
            output += red('The following leaks were detected:' + notebook.leaks.join(', ')) + '\n';
        }
        else {
            output += green('No global variable leaks detected') + '\n';
        }
    }

    // Coverage

    const coverage = notebook.coverage;
    if (coverage) {
        const status = 'Coverage: ' + coverage.percent.toFixed(2) + '%';

        output += coverage.percent === 100 ? green(status) : red(status + ' (' + (coverage.sloc - coverage.hits) + '/' + coverage.sloc + ')');
        if (coverage.percent < 100) {
            coverage.files.forEach((file) => {

                let missingLines;
                if (file.sourcemaps) {
                    const missingLinesByFile = {};
                    Object.keys(file.source).forEach((lineNumber) => {

                        const line = file.source[lineNumber];
                        if (line.miss) {
                            missingLines = missingLinesByFile[line.originalFilename] = missingLinesByFile[line.originalFilename] || [];
                            missingLines.push(line.originalLine);
                        }
                    });

                    const files = Object.keys(missingLinesByFile);
                    if (files.length) {
                        output += red('\n' + file.filename + ' missing coverage from file(s):');
                        files.forEach((filename) => {

                            output += red('\n\t' + filename + ' on line(s): ' + missingLinesByFile[filename].join(', '));
                        });
                    }
                }
                else {
                    missingLines = [];
                    Object.keys(file.source).forEach((lineNumber) => {

                        const line = file.source[lineNumber];
                        if (line.miss) {
                            missingLines.push(lineNumber);
                        }
                    });

                    if (missingLines.length) {
                        output += red('\n' + file.filename + ' missing coverage on line(s): ' + missingLines.join(', '));
                    }
                }
            });

            if (coverage.percent < this.settings.threshold || isNaN(coverage.percent)) {
                output += red('\nCode coverage below threshold: ' + coverage.percent.toFixed(2) + ' < ' + this.settings.threshold);
            }
        }

        output += '\n';
    }

    const lint = notebook.lint;
    if (lint) {
        output += 'Linting results:';

        let hasErrors = false;
        lint.lint.forEach((entry) => {

            // Don't show anything if there aren't issues
            if (!entry.errors || !entry.errors.length) {
                return;
            }

            hasErrors = true;
            output += gray('\n\t' + entry.filename + ':');
            entry.errors.forEach((err) => {

                output += (err.severity === 'ERROR' ? red : yellow)('\n\t\tLine ' + err.line + ': ' + err.message);
            });
        });

        if (!hasErrors) {
            output += green(' No issues\n');
        }
    }

    output += '\n';
    this.report(output);
};

internals.color = function (name, code, enabled) {

    if (enabled && Array.isArray(code)) {
        const color = '\u001b[' + code[0] + ';' + code[1] + 'm';
        return function (text) {

            return color + text + '\u001b[0m';
        };
    }
    else if (enabled) {
        const color = '\u001b[' + code + 'm';
        return function (text) {

            return color + text + '\u001b[0m';
        };
    }

    return function (text) {

        return text;
    };
};

internals.colors = function (enabled) {

    if (enabled === null) {
        enabled = Tty.isatty(1) && Tty.isatty(2);
    }

    const codes = {
        'black': 0,
        'gray': 90,
        'red': 31,
        'green': 32,
        'yellow': 33,
        'magenta': 35,
        'redBg': 41,
        'greenBg': 42,
        'whiteRedBg': [37, 41],
        'blackGreenBg': [30, 42]
    };

    const colors = {};
    const names = Object.keys(codes);
    for (let i = 0; i < names.length; ++i) {
        const name = names[i];
        colors[name] = internals.color(name, codes[name], enabled);
    }

    return colors;
};

internals.filterFailures = function (test) {

    return !!test.err;
};

internals.filterNodeModules = function (line) {

    return !(/\/node_modules\//.test(line));
};

internals.filterSkipped = function (test) {

    return test.skipped;
};
<commit_msg>Console reporter: Output number of skipped tests<commit_after>'use strict';

// Load modules

const Tty = require('tty');
const Diff = require('diff');
const StringifySafe = require('json-stringify-safe');

// Declare internals

const internals = {
    width: 50
};

exports = module.exports = internals.Reporter = function (options) {

    this.settings = options;
    this.count = 0;
    this.last = [];

    this.colors = internals.colors(options.colors);
};

internals.Reporter.prototype.start = function (notebook) {

};

internals.Reporter.prototype.test = function (test) {

    if (this.settings.progress === 0) {
        return;
    }

    if (this.settings.progress === 1) {

        // ..x....x.-..

        if (!this.count) {
            this.report('\n  ');
        }

        this.count++;

        if ((this.count - 1) % internals.width === 0) {
            this.report('\n  ');
        }

        this.report(test.err ? this.colors.red('x') : (test.skipped || test.todo ? this.colors.magenta('-') : '.'));
    }
    else {

        const check = process.platform === 'win32' ? '\u221A' : '\u2714';
        const asterisk = process.platform === 'win32' ? '\u00D7' : '\u2716';

        // Verbose (Spec reporter)

        for (let i = 0; i < test.path.length; ++i) {
            if (test.path[i] !== this.last[i]) {
                this.report(internals.spacer(i * 2) + test.path[i] + '\n');
            }
        }

        this.last = test.path;

        const spacer = internals.spacer(test.path.length * 2);
        if (test.err) {
            this.report(spacer + this.colors.red(asterisk + test.id + ') ' + test.relativeTitle) + '\n');
        }
        else {
            const symbol = test.skipped || test.todo ? this.colors.magenta('-') : this.colors.green(check);
            this.report(spacer + symbol + ' ' + this.colors.gray(test.id + ') ' + test.relativeTitle +
                ' (' + test.duration + ' ms)') + '\n');
        }
    }
};

internals.spacer = function (length) {

    return new Array(length + 1).join(' ');
};

internals.stringifyReplacer = function (key, value) {

    // Show usually invisible values from JSON.stringify in a different way,
    // follow the bracket format of json-stringify-safe.

    if (value === undefined) {
        return '[undefined]';
    }

    if (typeof value === 'function' || value === Infinity || value === -Infinity) {
        return '[' + value.toString() + ']';
    }

    /* $lab:coverage:off$ */ // There is no way to cover that in node 0.10
    if (typeof value === 'symbol') {
        return '[' + value.toString() + ']';
    }
    /* $lab:coverage:on$ */

    return value;
};

internals.Reporter.prototype.end = function (notebook) {

    if (this.settings.progress) {
        this.report('\n\n');
    }

    // Colors

    const red = this.colors.red;
    const green = this.colors.green;
    const gray = this.colors.gray;
    const yellow = this.colors.yellow;
    const whiteRedBg = this.colors.whiteRedBg;
    const blackGreenBg = this.colors.blackGreenBg;

    // Tests

    const failures = notebook.tests.filter(internals.filterFailures);

    const skipped = notebook.tests.filter(internals.filterSkipped);

    let output = '';
    const totalTests = notebook.tests.length - skipped.length;

    const errors = notebook.errors || [];
    if (errors.length) {
        output += 'Test script errors:\n\n';
        errors.forEach((err) => {

            output += red(err.message) + '\n';
            if (err.stack) {
                const stack = err.stack.slice(err.stack.indexOf('\n') + 1)
                                       .replace(/^/gm, '  ')
                                       .split('\n')
                                       .filter(internals.filterNodeModules)               // Remove node_modules files
                                       .slice(0, 5)                                       // Show only first 5 stack lines
                                       .join('\n');

                output += gray(stack) + '\n';
            }

            output += '\n';
        });
        output += red('There were ' + errors.length + ' test script error(s).') + '\n\n';
    }

    if (failures.length) {
        output += 'Failed tests:\n\n';

        for (let i = 0; i < failures.length; ++i) {
            const test = failures[i];
            const message = test.err.message || '';

            output += '  ' + test.id + ') ' + test.title + ':\n\n';

            // Actual vs Expected

            if (test.err.actual !== undefined &&
                test.err.expected !== undefined) {

                const actual = StringifySafe(test.err.actual, internals.stringifyReplacer, 2);
                const expected = StringifySafe(test.err.expected, internals.stringifyReplacer, 2);

                output += '      ' + whiteRedBg('actual') + ' ' + blackGreenBg('expected') + '\n\n      ';

                const comparison = Diff.diffWords(actual, expected);
                for (let j = 0; j < comparison.length; ++j) {
                    const item = comparison[j];
                    const value = item.value;
                    const lines = value.split('\n');
                    for (let k = 0; k < lines.length; ++k) {
                        if (k) {
                            output += '\n      ';
                        }

                        if (item.added || item.removed) {
                            output += item.added ? blackGreenBg(lines[k]) : whiteRedBg(lines[k]);
                        }
                        else {
                            output += lines[k];
                        }
                    }
                }

                output += '\n\n      ' + yellow(message);
                output += '\n\n';
            }
            else {
                output += '      ' + red(message) + '\n\n';
            }

            if (test.err.at) {
                output += gray('      at ' + test.err.at.filename + ':' + test.err.at.line + ':' + test.err.at.column) + '\n';
            }
            else if (!test.timeout &&
                test.err.stack) {

                output += gray(test.err.stack.slice(test.err.stack.indexOf('\n') + 1).replace(/^/gm, '  ')) + '\n';
            }

            if (test.err.data) {
                const isObject = typeof test.err.data === 'object' && !Array.isArray(test.err.data);
                let errorData = StringifySafe(test.err.data, null, isObject ? 4 : null);
                if (isObject) {
                    errorData = errorData.replace(/(\n\s*)"(.*)"\:/g, '$1$2:').split('\n').slice(1, -1).join('\n');
                }

                output += gray('\n      Additional error data:\n' + errorData.replace(/^/gm, '      ')) + '\n';
            }

            output += '\n';
        }

        output += '\n' + red(failures.length + ' of ' + totalTests + ' tests failed');
    }
    else {
        output += green(totalTests + ' tests complete');
    }
    if (skipped.length) {
        output += gray(` (${skipped.length} skipped)`);
    }
    output += '\n';
    output += 'Test duration: ' + notebook.ms + ' ms\n';

    // Assertions

    if (notebook.assertions !== undefined) {
        output += 'Assertions count: ' + notebook.assertions + ' (verbosity: ' + (notebook.assertions / totalTests).toFixed(2) + ')\n';
    }

    // Leaks

    if (notebook.leaks) {
        if (notebook.leaks.length) {
            output += red('The following leaks were detected:' + notebook.leaks.join(', ')) + '\n';
        }
        else {
            output += green('No global variable leaks detected') + '\n';
        }
    }

    // Coverage

    const coverage = notebook.coverage;
    if (coverage) {
        const status = 'Coverage: ' + coverage.percent.toFixed(2) + '%';

        output += coverage.percent === 100 ? green(status) : red(status + ' (' + (coverage.sloc - coverage.hits) + '/' + coverage.sloc + ')');
        if (coverage.percent < 100) {
            coverage.files.forEach((file) => {

                let missingLines;
                if (file.sourcemaps) {
                    const missingLinesByFile = {};
                    Object.keys(file.source).forEach((lineNumber) => {

                        const line = file.source[lineNumber];
                        if (line.miss) {
                            missingLines = missingLinesByFile[line.originalFilename] = missingLinesByFile[line.originalFilename] || [];
                            missingLines.push(line.originalLine);
                        }
                    });

                    const files = Object.keys(missingLinesByFile);
                    if (files.length) {
                        output += red('\n' + file.filename + ' missing coverage from file(s):');
                        files.forEach((filename) => {

                            output += red('\n\t' + filename + ' on line(s): ' + missingLinesByFile[filename].join(', '));
                        });
                    }
                }
                else {
                    missingLines = [];
                    Object.keys(file.source).forEach((lineNumber) => {

                        const line = file.source[lineNumber];
                        if (line.miss) {
                            missingLines.push(lineNumber);
                        }
                    });

                    if (missingLines.length) {
                        output += red('\n' + file.filename + ' missing coverage on line(s): ' + missingLines.join(', '));
                    }
                }
            });

            if (coverage.percent < this.settings.threshold || isNaN(coverage.percent)) {
                output += red('\nCode coverage below threshold: ' + coverage.percent.toFixed(2) + ' < ' + this.settings.threshold);
            }
        }

        output += '\n';
    }

    const lint = notebook.lint;
    if (lint) {
        output += 'Linting results:';

        let hasErrors = false;
        lint.lint.forEach((entry) => {

            // Don't show anything if there aren't issues
            if (!entry.errors || !entry.errors.length) {
                return;
            }

            hasErrors = true;
            output += gray('\n\t' + entry.filename + ':');
            entry.errors.forEach((err) => {

                output += (err.severity === 'ERROR' ? red : yellow)('\n\t\tLine ' + err.line + ': ' + err.message);
            });
        });

        if (!hasErrors) {
            output += green(' No issues\n');
        }
    }

    output += '\n';
    this.report(output);
};

internals.color = function (name, code, enabled) {

    if (enabled && Array.isArray(code)) {
        const color = '\u001b[' + code[0] + ';' + code[1] + 'm';
        return function (text) {

            return color + text + '\u001b[0m';
        };
    }
    else if (enabled) {
        const color = '\u001b[' + code + 'm';
        return function (text) {

            return color + text + '\u001b[0m';
        };
    }

    return function (text) {

        return text;
    };
};

internals.colors = function (enabled) {

    if (enabled === null) {
        enabled = Tty.isatty(1) && Tty.isatty(2);
    }

    const codes = {
        'black': 0,
        'gray': 90,
        'red': 31,
        'green': 32,
        'yellow': 33,
        'magenta': 35,
        'redBg': 41,
        'greenBg': 42,
        'whiteRedBg': [37, 41],
        'blackGreenBg': [30, 42]
    };

    const colors = {};
    const names = Object.keys(codes);
    for (let i = 0; i < names.length; ++i) {
        const name = names[i];
        colors[name] = internals.color(name, codes[name], enabled);
    }

    return colors;
};

internals.filterFailures = function (test) {

    return !!test.err;
};

internals.filterNodeModules = function (line) {

    return !(/\/node_modules\//.test(line));
};

internals.filterSkipped = function (test) {

    return test.skipped;
};
<|endoftext|>


<commit_before>var body = document.body;
var html = document.documentElement;
var table = document.getElementsByClassName('snaketable')[0];

var size = 30; // Size of cell
var height = 10;
var width = 15;

table.setAttribute('height', height*size + 'px');
table.setAttribute('width', width*size + 'px');
table.setAttribute('cellspacing', '1px');
table.setAttribute('cellpadding', '0px');
for (var i=0; i<height; i+=1) {
	var row = table.insertRow(i);
	for (var j=0; j<width; j+=1) {
		var cell = row.insertCell(j);
		cell.setAttribute('name', j+'_'+i);
		var btn = document.createElement('button');
		btn.setAttribute('class', 'invisible');
		btn.setAttribute('onmousedown', 'placeFood('+j+','+i+')');
		btn.style.height = size+'px';
		btn.style.width = size+'px';
		cell.appendChild(btn);
	}
}

function updateBoard() {
	for (var r=0; r<table.rows.length; r++) {
		for (var c=0; c<table.rows[r].cells.length; c++) {
			var cell = table.rows[r].cells[c];
			if (inSnakeTwice(cell.getAttribute('name'))) {
				cell.setAttribute('class', 'impactcell');
			} else if (inSnake(cell.getAttribute('name'))) {
				cell.setAttribute('class', 'snakecell');
			} else if (cell.getAttribute('name') == food[0]+'_'+food[1]) {
				cell.setAttribute('class', 'foodcell');
			} else {
				cell.setAttribute('class', 'emptycell');
			}
			cell.setAttribute('height', size+'px');
			cell.setAttribute('width', size+'px');
		}
	}
	score.innerHTML = (snake.length - level - 3);
	var minutes, seconds;
	//console.log("Before minutes and seconds are calculated");
	if (startTime == []) { // Before stage start
		time.innerHTML = '0:00.00';
	} else if (stopTime == []) { // After stage end
		minutes = (stopTime[0] - startTime[0] + 60) % 60;
		seconds = (stopTime[1] - startTime[1] + 60) % 60;
	} else { // Stage in progress
		var minutes = (new Date().getMinutes() - startTime[0] + 60) % 60;
		var seconds = (new Date().getSeconds() - startTime[1] + 60) % 60;
	}
	//console.log("Minutes and seconds");
	time.innerHTML = minutes + ':' + (seconds<10?'0':'')+seconds;
}

updateBoard();
<commit_msg>Fixed time at start - now 0<commit_after>var body = document.body;
var html = document.documentElement;
var table = document.getElementsByClassName('snaketable')[0];

var size = 30; // Size of cell
var height = 10;
var width = 15;

table.setAttribute('height', height*size + 'px');
table.setAttribute('width', width*size + 'px');
table.setAttribute('cellspacing', '1px');
table.setAttribute('cellpadding', '0px');
for (var i=0; i<height; i+=1) {
	var row = table.insertRow(i);
	for (var j=0; j<width; j+=1) {
		var cell = row.insertCell(j);
		cell.setAttribute('name', j+'_'+i);
		var btn = document.createElement('button');
		btn.setAttribute('class', 'invisible');
		btn.setAttribute('onmousedown', 'placeFood('+j+','+i+')');
		btn.style.height = size+'px';
		btn.style.width = size+'px';
		cell.appendChild(btn);
	}
}

function updateBoard() {
	for (var r=0; r<table.rows.length; r++) {
		for (var c=0; c<table.rows[r].cells.length; c++) {
			var cell = table.rows[r].cells[c];
			if (inSnakeTwice(cell.getAttribute('name'))) {
				cell.setAttribute('class', 'impactcell');
			} else if (inSnake(cell.getAttribute('name'))) {
				cell.setAttribute('class', 'snakecell');
			} else if (cell.getAttribute('name') == food[0]+'_'+food[1]) {
				cell.setAttribute('class', 'foodcell');
			} else {
				cell.setAttribute('class', 'emptycell');
			}
			cell.setAttribute('height', size+'px');
			cell.setAttribute('width', size+'px');
		}
	}
	score.innerHTML = (snake.length - level - 3);
	var minutes, seconds;
	if (startTime.length == []) { // Before stage start
		time.innerHTML = '0:00';
	} else if (stopTime == []) { // After stage end
		minutes = (stopTime[0] - startTime[0] + 60) % 60;
		seconds = (stopTime[1] - startTime[1] + 60) % 60;
		time.innerHTML = minutes + ':' + (seconds<10?'0':'')+seconds;
	} else { // Stage in progress
		var minutes = (new Date().getMinutes() - startTime[0] + 60) % 60;
		var seconds = (new Date().getSeconds() - startTime[1] + 60) % 60;
		time.innerHTML = minutes + ':' + (seconds<10?'0':'')+seconds;
	}
}

updateBoard();
<|endoftext|>


<commit_before>/*global logger*/
/*
    DataviewLoader
    ========================

    @file      : DataviewLoader.js
    @version   : 1.3.1
    @author    : JvdGraaf
    @date      : Mon, 24 Apr 2017 15:02:42 GMT
    @copyright : Appronto
    @license   : Apache2

    Documentation
    ========================
    Describe your widget here.
*/

// Required module list. Remove unnecessary modules, you can always get them back from the boilerplate.

define([
  "dojo/_base/declare",
  "mxui/widget/_WidgetBase",
  "dijit/_TemplatedMixin",

  "mxui/dom",
  "dojo/dom",
  "dojo/dom-style",
  "dojo/dom-class",
  "dojo/_base/lang",
  "dojo/_base/event",

  "dojo/text!DataviewLoader/widget/template/DataviewLoader.html"
], function (declare, _WidgetBase, _TemplatedMixin, dom, dojoDom, dojoStyle, dojoClass, dojoLang, dojoEvent, widgetTemplate) {
    "use strict";

    // Declare widget's prototype.
    return declare("DataviewLoader.widget.DataviewLoader", [_WidgetBase, _TemplatedMixin], {
        // _TemplatedMixin will create our dom node using this HTML template.
        templateString: widgetTemplate,

        // DOM elements
        divContent: null,
        divLoader: null,

        // Internal variables. Non-primitives created in the prototype are shared between all widget instances.
        _handles: null,
        _contextObj: null,
        _loadingStarted: false,
        _pageInitiated: false,
        _form: null,
        active: true,
        prevForm: null,
        refreshHandler: null,
        // dojo.declare.constructor is called to construct the widget instance. Implement to initialize non-primitive properties.
        constructor: function () {
            //logger.debug(this.id + ".constructor");
            this._handles = [];
        },

        // dijit._WidgetBase.postCreate is called after constructing the widget. Implement to do extra setup work.
        postCreate: function () {
            logger.debug(this.id + ".postCreate");

            this._updateRendering();
            this._setupEvents();
        },

        // mxui.widget._WidgetBase.update is called when context is changed or initialized. Implement to re-render and / or fetch data.
        update: function (obj, callback) {
            if (this._contextObj !== obj) {
                console.log(this.id + ".update on new object");
                this._loadingStarted = false;
                this._pageInitiated = false;

                this._contextObj = obj;
                this._resetSubscriptions();
                this._updateRendering(callback); // We're passing the callback to updateRendering to be called after DOM-manipulation
            } else {
                // The callback, coming from update, needs to be executed, to let the page know it finished rendering
                this._executeCallback(callback, "update");
            }
        },

        // mxui.widget._WidgetBase.enable is called when the widget should enable editing. Implement to enable editing if widget is input widget.
        enable: function () {
            logger.debug(this.id + ".enable");
        },

        // mxui.widget._WidgetBase.enable is called when the widget should disable editing. Implement to disable editing if widget is input widget.
        disable: function () {
            logger.debug(this.id + ".disable");
        },

        // mxui.widget._WidgetBase.resize is called when the page's layout is recalculated. Implement to do sizing calculations. Prefer using CSS instead.
        resize: function (box) {
            console.log(this.id + ".resize");
            // TODO: How to handle tabs and conditional visibility
            if (this.domNode.offsetParent !== null && this.visibilityCheck) {
                if (this.refreshAction == "Attribute" && this.refreshtAttr && this._contextObj) {
                    if (this._contextObj.get(this.refreshtAttr))
                        this._loadAndShowcontent();
                    else
                        console.log(this.id + ".resize Skip because " + this.refreshtAttr + " is false");
                } else {
                    this._loadAndShowcontent();
                }
            }
        },

        // mxui.widget._WidgetBase.uninitialize is called when the widget is destroyed. Implement to do special tear-down work.
        uninitialize: function () {
            logger.debug(this.id + ".uninitialize");
            // Clean up listeners, helper objects, etc. There is no need to remove listeners added with this.connect / this.subscribe / this.own.
            this.active = false;
            if (this.refreshHandler) {
                clearInterval(this.refreshHandler);
                this.refreshHandler = null;
            }
            if (this._form != null) {
                this._form.destroy();
            }
        },

        // We want to stop events on a mobile device
        _stopBubblingEventOnMobile: function (e) {
            logger.debug(this.id + "._stopBubblingEventOnMobile");
            if (typeof document.ontouchstart !== "undefined") {
                dojoEvent.stop(e);
            }
        },

        // Attach events to HTML dom elements
        _setupEvents: function () {
            // Set fading of content
            if (this.fadeContent) {
                dojoClass.add(this.divContent, "loaderfade");
            }

            // Set refreshing each time
            if (this.refreshTime > 0) {
                this.refreshHandler = setInterval(dojoLang.hitch(this, function () {
                    if (this._loadingStarted == false) {
                        if (this.pageMF) {
                            this._pageInitiated = false;
                        }
                        this._updateRendering();
                    } else {
                        console.log(this.id + ".Refresh skip because of loading started.");
                    }
                }), this.refreshTime * 1000);
            }
        },

        // Rerender the interface.
        _updateRendering: function (callback) {
            logger.debug(this.id + "._updateRendering");

            try{
                if (this._contextObj) {
                    if (this.loadingText && this.divLoader.innerHTML.indexOf(this.loadingText) === -1) {
                        var text = "

" + this.loadingText + "

";
                        this.divLoader.innerHTML = text + this.divLoader.innerHTML;
                    }

                    dojoStyle.set(this.divContent, "display", "none");
                    dojoStyle.set(this.divLoader, "display", "block");

                    if (this.domNode.offsetParent !== null || !this.visibilityCheck) {
                        this._loadAndShowcontent();
                    }
                }

                // The callback, coming from update, needs to be executed, to let the page know it finished rendering
                this._executeCallback(callback, "_updateRendering");
            } catch(error){
                console.log(this.id + "._updateRendering error occurred: " + JSON.stringify(error));
            }
        },

        _loadAndShowcontent: function () {
            logger.debug(this.id + "._loadAndShowcontent");
            if (this._loadingStarted == false) {
                this._loadingStarted = true;
                if (this._contextObj && this.loadingMF) {
                    this._execMf(this.loadingMF, this._contextObj.getGuid(), this._processMicroflowCallback, this._processMicroflowFailure);
                } else if (this._contextObj) {
                    this._setPage(this._contextObj);
                }
            }
        },

        _processMicroflowCallback: function (objs) {
            logger.debug(this.id + '._processMicroflowCallback');
            if (this.active) {
                if (this.asyncCall)
                    this._setPage(this._contextObj);
                else
                    this._setPage(objs[0]);
            } else {
                console.info(this.id + "._processMicroflowCallback Skip loading because widget is destroyed.");
            }
        },
        _processMicroflowFailure: function () {
            if (this.errorText) {
                if (this._pageInitiated)
                    this._form.close();
                this._pageInitiated = false;
                this.divContent.innerHTML = "

" + this.errorText + "

";

                this._showPage();
            }
        },

        _openFormByFormProp: function (pageContext) {
            var props = {
                location: "node",
                domNode: this.divContent,
                callback: dojoLang.hitch(this, this._showPage),
                error: function (error) {
                    console.log(error.description);
                }
            };

            if (pageContext)
                props.context = pageContext;
            this._form = mx.ui.openForm(this.pageContent, props);
        },

        _openFormByMF: function (pageObj, pageContext) {
            this._execMf(this.pageMF, pageObj.getGuid(), function (response) {
                this._form = mx.ui.openForm(response, {
                    context: pageContext,
                    location: "node",
                    domNode: this.divContent,
                    callback: dojoLang.hitch(this, this._showPage),
                    error: function (error) {
                        console.log(error.description);
                    }
                });
            }, function () {
                alert("Error bij aanroepen custom form MF");
            });
        },

        _setPage: function (pageObj) {
            logger.debug(this.id + '._setPage');

            if (this._pageInitiated) {
                if (this._loadingStarted) {
                    this._showPage();
                } else {
                    console.log(this.id + "_setPage skip because already set.");
                }
            } else {
                this._pageInitiated = true;
                this.divContent.innerHTML = "";
                console.log(this.id + "_setPage");
                if (pageObj) {
                    var pageContext = new mendix.lib.MxContext();
                    pageContext.setTrackObject(pageObj);

                    if (this.pageMF != null && this.pageMF != '')
                        this._openFormByMF(pageObj, pageContext);
                    else
                        this._openFormByFormProp(pageContext);

                } else {
                    if (this.pageMF != null && this.pageMF != '')
                        alert("Page microflow is not supported without context");
                    else
                        this._openFormByFormProp();

                }
            }
        },

        _showPage: function (mxform) {
            logger.debug(this.id + "._showPage on form");

            if (this.prevForm != null && mxform != null) {
                this.prevForm.destroy();
            }
            this.prevForm = mxform;

            dojoStyle.set(this.divContent, "display", "block");
            dojoStyle.set(this.divLoader, "display", "none");

            this._loadingStarted = false;
        },

        // Reset subscriptions.
        _resetSubscriptions: function () {
            logger.debug(this.id + "._resetSubscriptions");
            // Release handles on previous object, if any.
            this.unsubscribeAll();

            // When a mendix object exists create subscribtions.
            if (this._contextObj && (this.refreshAction === "Object" || this.refreshAction === "Attribute")) {
                console.log(this.id + "._resetSubscriptions setup refresh handler: " + this.refreshAction);
                this.subscribe({
                    guid: this._contextObj.getGuid(),
                    callback: dojoLang.hitch(this, function (guid) {
                        if (this._loadingStarted == false) {
                            if (this.pageMF) {
                                this._pageInitiated = false;
                            }
                            if (this.refreshAction == "Attribute" && this.refreshtAttr && this._contextObj.get(this.refreshtAttr)) {
                                console.log(this.id + ".Refresh triggered on attribute change.");
                                this._updateRendering();
                            } else if (this.refreshAction == "Object") {
                                console.log(this.id + ".Refresh triggered on object change.");
                                this._updateRendering();
                            }
                        } else {
                            console.log(this.id + ".Refresh skip because of loading started.");
                        }
                    })
                });
            }
        },

        _execMf: function (mf, guid, cb, cbfailure) {
            logger.debug(this.id + "._execMf" + (mf ? ": " + mf : ""));
            if (mf && guid) {
                mx.data.action({
                    params: {
                        applyto: "selection",
                        actionname: mf,
                        guids: [guid]
                    },
                    async: this.asyncCall,
                    origin: this.mxform,
                    callback: (cb && typeof cb === "function" ? dojoLang.hitch(this, cb) : null),
                    error: (cbfailure && typeof cbfailure === "function" ? dojoLang.hitch(this, cbfailure) : null)
                });
            }
        },

        _executeCallback: function (cb, from) {
            logger.debug(this.id + "._executeCallback" + (from ? " from " + from : ""));
            if (cb && typeof cb === "function") {
                cb();
            }
        }
    });
});

require(["DataviewLoader/widget/DataviewLoader"]);<commit_msg>Always callback<commit_after>/*global logger*/
/*
    DataviewLoader
    ========================

    @file      : DataviewLoader.js
    @version   : 1.3.1
    @author    : JvdGraaf
    @date      : Mon, 24 Apr 2017 15:02:42 GMT
    @copyright : Appronto
    @license   : Apache2

    Documentation
    ========================
    Describe your widget here.
*/

// Required module list. Remove unnecessary modules, you can always get them back from the boilerplate.

define([
  "dojo/_base/declare",
  "mxui/widget/_WidgetBase",
  "dijit/_TemplatedMixin",

  "mxui/dom",
  "dojo/dom",
  "dojo/dom-style",
  "dojo/dom-class",
  "dojo/_base/lang",
  "dojo/_base/event",

  "dojo/text!DataviewLoader/widget/template/DataviewLoader.html"
], function (declare, _WidgetBase, _TemplatedMixin, dom, dojoDom, dojoStyle, dojoClass, dojoLang, dojoEvent, widgetTemplate) {
    "use strict";

    // Declare widget's prototype.
    return declare("DataviewLoader.widget.DataviewLoader", [_WidgetBase, _TemplatedMixin], {
        // _TemplatedMixin will create our dom node using this HTML template.
        templateString: widgetTemplate,

        // DOM elements
        divContent: null,
        divLoader: null,

        // Internal variables. Non-primitives created in the prototype are shared between all widget instances.
        _handles: null,
        _contextObj: null,
        _loadingStarted: false,
        _pageInitiated: false,
        _form: null,
        active: true,
        prevForm: null,
        refreshHandler: null,
        // dojo.declare.constructor is called to construct the widget instance. Implement to initialize non-primitive properties.
        constructor: function () {
            //logger.debug(this.id + ".constructor");
            this._handles = [];
        },

        // dijit._WidgetBase.postCreate is called after constructing the widget. Implement to do extra setup work.
        postCreate: function () {
            logger.debug(this.id + ".postCreate");

            this._updateRendering();
            this._setupEvents();
        },

        // mxui.widget._WidgetBase.update is called when context is changed or initialized. Implement to re-render and / or fetch data.
        update: function (obj, callback) {
            if (this._contextObj !== obj) {
                console.log(this.id + ".update on new object");
                this._loadingStarted = false;
                this._pageInitiated = false;

                this._contextObj = obj;
                this._resetSubscriptions();
                this._updateRendering();
            }
            if (callback) {
                callback();
            }
        },

        // mxui.widget._WidgetBase.enable is called when the widget should enable editing. Implement to enable editing if widget is input widget.
        enable: function () {
            logger.debug(this.id + ".enable");
        },

        // mxui.widget._WidgetBase.enable is called when the widget should disable editing. Implement to disable editing if widget is input widget.
        disable: function () {
            logger.debug(this.id + ".disable");
        },

        // mxui.widget._WidgetBase.resize is called when the page's layout is recalculated. Implement to do sizing calculations. Prefer using CSS instead.
        resize: function (box) {
            console.log(this.id + ".resize");
            // TODO: How to handle tabs and conditional visibility
            if (this.domNode.offsetParent !== null && this.visibilityCheck) {
                if (this.refreshAction == "Attribute" && this.refreshtAttr && this._contextObj) {
                    if (this._contextObj.get(this.refreshtAttr))
                        this._loadAndShowcontent();
                    else
                        console.log(this.id + ".resize Skip because " + this.refreshtAttr + " is false");
                } else {
                    this._loadAndShowcontent();
                }
            }
        },

        // mxui.widget._WidgetBase.uninitialize is called when the widget is destroyed. Implement to do special tear-down work.
        uninitialize: function () {
            logger.debug(this.id + ".uninitialize");
            // Clean up listeners, helper objects, etc. There is no need to remove listeners added with this.connect / this.subscribe / this.own.
            this.active = false;
            if (this.refreshHandler) {
                clearInterval(this.refreshHandler);
                this.refreshHandler = null;
            }
            if (this._form != null) {
                this._form.destroy();
            }
        },

        // We want to stop events on a mobile device
        _stopBubblingEventOnMobile: function (e) {
            logger.debug(this.id + "._stopBubblingEventOnMobile");
            if (typeof document.ontouchstart !== "undefined") {
                dojoEvent.stop(e);
            }
        },

        // Attach events to HTML dom elements
        _setupEvents: function () {
            // Set fading of content
            if (this.fadeContent) {
                dojoClass.add(this.divContent, "loaderfade");
            }

            // Set refreshing each time
            if (this.refreshTime > 0) {
                this.refreshHandler = setInterval(dojoLang.hitch(this, function () {
                    if (this._loadingStarted == false) {
                        if (this.pageMF) {
                            this._pageInitiated = false;
                        }
                        this._updateRendering();
                    } else {
                        console.log(this.id + ".Refresh skip because of loading started.");
                    }
                }), this.refreshTime * 1000);
            }
        },

        // Rerender the interface.
        _updateRendering: function () {
            logger.debug(this.id + "._updateRendering");

            try{
                if (this._contextObj) {
                    if (this.loadingText && this.divLoader.innerHTML.indexOf(this.loadingText) === -1) {
                        var text = "

" + this.loadingText + "

";
                        this.divLoader.innerHTML = text + this.divLoader.innerHTML;
                    }

                    dojoStyle.set(this.divContent, "display", "none");
                    dojoStyle.set(this.divLoader, "display", "block");

                    if (this.domNode.offsetParent !== null || !this.visibilityCheck) {
                        this._loadAndShowcontent();
                    }
                }
            } catch(error){
                console.log(this.id + "._updateRendering error occurred: " + JSON.stringify(error));
            }
        },

        _loadAndShowcontent: function () {
            logger.debug(this.id + "._loadAndShowcontent");
            if (this._loadingStarted == false) {
                this._loadingStarted = true;
                if (this._contextObj && this.loadingMF) {
                    this._execMf(this.loadingMF, this._contextObj.getGuid(), this._processMicroflowCallback, this._processMicroflowFailure);
                } else if (this._contextObj) {
                    this._setPage(this._contextObj);
                }
            }
        },

        _processMicroflowCallback: function (objs) {
            logger.debug(this.id + '._processMicroflowCallback');
            if (this.active) {
                if (this.asyncCall)
                    this._setPage(this._contextObj);
                else
                    this._setPage(objs[0]);
            } else {
                console.info(this.id + "._processMicroflowCallback Skip loading because widget is destroyed.");
            }
        },
        _processMicroflowFailure: function () {
            if (this.errorText) {
                if (this._pageInitiated)
                    this._form.close();
                this._pageInitiated = false;
                this.divContent.innerHTML = "

" + this.errorText + "

";

                this._showPage();
            }
        },

        _openFormByFormProp: function (pageContext) {
            var props = {
                location: "node",
                domNode: this.divContent,
                callback: dojoLang.hitch(this, this._showPage),
                error: function (error) {
                    console.log(error.description);
                }
            };

            if (pageContext)
                props.context = pageContext;
            this._form = mx.ui.openForm(this.pageContent, props);
        },

        _openFormByMF: function (pageObj, pageContext) {
            this._execMf(this.pageMF, pageObj.getGuid(), function (response) {
                this._form = mx.ui.openForm(response, {
                    context: pageContext,
                    location: "node",
                    domNode: this.divContent,
                    callback: dojoLang.hitch(this, this._showPage),
                    error: function (error) {
                        console.log(error.description);
                    }
                });
            }, function () {
                alert("Error bij aanroepen custom form MF");
            });
        },

        _setPage: function (pageObj) {
            logger.debug(this.id + '._setPage');

            if (this._pageInitiated) {
                if (this._loadingStarted) {
                    this._showPage();
                } else {
                    console.log(this.id + "_setPage skip because already set.");
                }
            } else {
                this._pageInitiated = true;
                this.divContent.innerHTML = "";
                console.log(this.id + "_setPage");
                if (pageObj) {
                    var pageContext = new mendix.lib.MxContext();
                    pageContext.setTrackObject(pageObj);

                    if (this.pageMF != null && this.pageMF != '')
                        this._openFormByMF(pageObj, pageContext);
                    else
                        this._openFormByFormProp(pageContext);

                } else {
                    if (this.pageMF != null && this.pageMF != '')
                        alert("Page microflow is not supported without context");
                    else
                        this._openFormByFormProp();

                }
            }
        },

        _showPage: function (mxform) {
            logger.debug(this.id + "._showPage on form");

            if (this.prevForm != null && mxform != null) {
                this.prevForm.destroy();
            }
            this.prevForm = mxform;

            dojoStyle.set(this.divContent, "display", "block");
            dojoStyle.set(this.divLoader, "display", "none");

            this._loadingStarted = false;
        },

        // Reset subscriptions.
        _resetSubscriptions: function () {
            logger.debug(this.id + "._resetSubscriptions");
            // Release handles on previous object, if any.
            this.unsubscribeAll();

            // When a mendix object exists create subscribtions.
            if (this._contextObj && (this.refreshAction === "Object" || this.refreshAction === "Attribute")) {
                console.log(this.id + "._resetSubscriptions setup refresh handler: " + this.refreshAction);
                this.subscribe({
                    guid: this._contextObj.getGuid(),
                    callback: dojoLang.hitch(this, function (guid) {
                        if (this._loadingStarted == false) {
                            if (this.pageMF) {
                                this._pageInitiated = false;
                            }
                            if (this.refreshAction == "Attribute" && this.refreshtAttr && this._contextObj.get(this.refreshtAttr)) {
                                console.log(this.id + ".Refresh triggered on attribute change.");
                                this._updateRendering();
                            } else if (this.refreshAction == "Object") {
                                console.log(this.id + ".Refresh triggered on object change.");
                                this._updateRendering();
                            }
                        } else {
                            console.log(this.id + ".Refresh skip because of loading started.");
                        }
                    })
                });
            }
        },

        _execMf: function (mf, guid, cb, cbfailure) {
            logger.debug(this.id + "._execMf" + (mf ? ": " + mf : ""));
            if (mf && guid) {
                mx.data.action({
                    params: {
                        applyto: "selection",
                        actionname: mf,
                        guids: [guid]
                    },
                    async: this.asyncCall,
                    origin: this.mxform,
                    callback: (cb && typeof cb === "function" ? dojoLang.hitch(this, cb) : null),
                    error: (cbfailure && typeof cbfailure === "function" ? dojoLang.hitch(this, cbfailure) : null)
                });
            }
        }
    });
});

require(["DataviewLoader/widget/DataviewLoader"]);<|endoftext|>


<commit_before>var fs = require("fs");
var log = require("ringo/logging").getLogger(module.id);
var compress = require("./compress");
var registry = require("./registry");
var config = require("./config");
var semver = require("./semver");
var os = require("./os");
var strings = require("ringo/utils/strings");
var descriptors = require("./descriptors");
var engine = require("ringo/engine");

export("isActivated", "isInstalled", "install", "uninstall", "activate",
        "deactivate", "getDescriptor", "getPackagesDir", "getInstallDir",
        "getInstalledVersions", "getLatestInstalledVersion", "getActivatedVersions",
        "getLatestInstalledVersions", "getActivatedVersion", "isManaged",
        "checkEngineDependencies");

function getInstallDir(name, version) {
    var dir = fs.join(config.ringoHome, "/packages.available/");
    if (name && version) {
        dir = fs.join(dir, name + "-" + version);
    }
    return fs.normal(dir);
}

function getPackagesDir() {
    return fs.normal(fs.join(config.ringoHome, "/packages/"));
}

/**
 * Returns true if a package with the given name is installed. If a version
 * number is specified, this method returns true if the exact package version
 * is installed, otherwise it returns true if at least one version of the
 * named package is installed.
 * @param {String} name The name of the package
 * @param {String} version Optional version number
 * @returns True if the package is installed
 * @type Boolean
 */
function isInstalled(name, version) {
    if (version == undefined) {
        return getInstalledVersions(name).length > 0;
    }
    return fs.exists(getInstallDir(name, version));
}

/**
 * Returns true if the link in package directory points to a module
 * installed in packages.available
 * @param {String} path The directory containing the module
 * @returns True if the package seems to be installed by rp, false otherwise
 * @type Boolean
 */
function isManaged(path) {
    var linkTarget = fs.resolve(getPackagesDir(), fs.readLink(path));
    return strings.startsWith(linkTarget, getInstallDir());
}

function isActivated(name, version) {
    var activatedVersion = getActivatedVersion(name);
    if (activatedVersion !== null) {
        if (version == undefined) {
            return true;
        }
        return activatedVersion == version;
    }
    return false;
}

function getInstalledVersions(name) {
    var list = fs.list(getInstallDir()).filter(function(dirName) {
        return dirName.substring(0, dirName.lastIndexOf("-")) == name;
    }).map(function(dirName) {
        return dirName.substring(dirName.lastIndexOf("-") + 1);
    });
    if (list.length > 1) {
        semver.sort(list, -1);
    }
    return list;
}

/**
 * Returns the latest installed version of the specified package
 * @param {String} name The package name
 * @returns The latest installed version of the package
 * @type String
 */
function getLatestInstalledVersion(name) {
    return getInstalledVersions(name)[0] || null;
}

function getLatestInstalledVersions() {
    var result = {};
    var list = fs.list(getInstallDir());
    for each (let dirName in list) {
        if (strings.startsWith(dirName, ".")) {
            continue;
        }
        var descriptor = getDescriptor(fs.join(getInstallDir(), dirName));
        if (descriptor === null) {
            continue;
        }
        if (!Object.hasOwnProperty(result, descriptor.name) ||
                !semver.isGreater(descriptor.version, result[descriptor.name])) {
            result[descriptor.name] = descriptor.version;
        }
    }
    return result;
}

function getActivatedVersion(name) {
    var link = fs.join(getPackagesDir(), name);
    if (fs.exists(link)) {
        var activePackage = getDescriptor(link);
        if (activePackage != null) {
            return activePackage.version;
        }
    }
    return null;
}

function getActivatedVersions() {
    var result = {};
    var list = fs.list(getPackagesDir());
    for each (let name in list) {
        var version = getActivatedVersion(name);
        if (version !== null) {
            result[name] = version;
        }
    }
    return result;
}

function getDescriptor(dir) {
    var jsonPath = fs.normal(fs.join(dir, "package.json"));
    if (fs.exists(jsonPath)) {
        return JSON.parse(fs.read(jsonPath));
    }
    return null;
}

function install(archivePath, name, version) {
    var installDir = getInstallDir(name, version);
    log.debug("Installing", fs.base(archivePath), "in", installDir);
    if (!fs.exists(installDir)) {
        fs.makeTree(installDir);
        var fileStream = fs.open(archivePath, {
            "binary": true
        });
        compress.extractStream(fileStream, installDir);
        log.debug("Installed", name, version, "in", installDir);
    }
    return installDir;
}

function uninstall(name, version) {
    var installDir = getInstallDir(name, version);
    if (!fs.exists(installDir)) {
        throw new Error("The package " + name + " " + version + " isn't installed")
    }
    fs.removeTree(installDir);
    log.debug("Uninstalled", name, version, "in", installDir);
    return installDir;
}

function activate(name, version) {
    if (os.isWindows()) {
        throw new Error("Package activation isn't supported on Windows. Please do it manually.");
    }
    var installDir = getInstallDir(name, version);
    var packagesDir = getPackagesDir();
    if (!fs.exists(installDir)) {
        throw new Error("The package " + name + " " + version + " isn't installed");
    }
    var src = fs.relative(packagesDir, installDir);
    var dest = fs.join(packagesDir, name);
    if (fs.exists(dest)) {
        if (!fs.isLink(dest)) {
            throw new Error("Package " + name +
                    " has been copied into packages directory, please move it away manually");
        } else if (!isManaged(dest)) {
            throw new Error(name + " wasn't installed by rp, please deactivate manually");
        }
        fs.removeDirectory(dest);
    }
    if (fs.symbolicLink(src, dest) < 0) {
        throw new Error("Unable to activate the package " + name);
    }
    log.debug("Activated", name, version, "in", packagesDir);
    return dest;
}

function deactivate(name) {
    if (os.isWindows()) {
        throw new Error("Package deactivation isn't supported on Windows. Please do it manually.");
    }
    var path = fs.normal(fs.join(getPackagesDir(), name));
    if (!fs.exists(path)) {
        throw new Error("The package " + name + " is not activated");
    } else if (!fs.isLink(path)) {
        throw new Error("Package " + name +
                " has been copied into packages directory, please move it away manually");
    } else if (!isManaged(path)) {
        throw new Error(name + " wasn't installed by rp, please deactivate manually");
    }
    // FIXME: remove() doesn't allow removing symlinks to directories
    fs.removeDirectory(path);
    log.debug("Deactivated", path);
    return;
}
<commit_msg>modified install to make all files in bin directory of installed package executable<commit_after>var fs = require("fs");
var log = require("ringo/logging").getLogger(module.id);
var compress = require("./compress");
var registry = require("./registry");
var config = require("./config");
var semver = require("./semver");
var os = require("./os");
var strings = require("ringo/utils/strings");
var descriptors = require("./descriptors");
var engine = require("ringo/engine");

export("isActivated", "isInstalled", "install", "uninstall", "activate",
        "deactivate", "getDescriptor", "getPackagesDir", "getInstallDir",
        "getInstalledVersions", "getLatestInstalledVersion", "getActivatedVersions",
        "getLatestInstalledVersions", "getActivatedVersion", "isManaged",
        "checkEngineDependencies");

function getInstallDir(name, version) {
    var dir = fs.join(config.ringoHome, "/packages.available/");
    if (name && version) {
        dir = fs.join(dir, name + "-" + version);
    }
    return fs.normal(dir);
}

function getPackagesDir() {
    return fs.normal(fs.join(config.ringoHome, "/packages/"));
}

/**
 * Returns true if a package with the given name is installed. If a version
 * number is specified, this method returns true if the exact package version
 * is installed, otherwise it returns true if at least one version of the
 * named package is installed.
 * @param {String} name The name of the package
 * @param {String} version Optional version number
 * @returns True if the package is installed
 * @type Boolean
 */
function isInstalled(name, version) {
    if (version == undefined) {
        return getInstalledVersions(name).length > 0;
    }
    return fs.exists(getInstallDir(name, version));
}

/**
 * Returns true if the link in package directory points to a module
 * installed in packages.available
 * @param {String} path The directory containing the module
 * @returns True if the package seems to be installed by rp, false otherwise
 * @type Boolean
 */
function isManaged(path) {
    var linkTarget = fs.resolve(getPackagesDir(), fs.readLink(path));
    return strings.startsWith(linkTarget, getInstallDir());
}

function isActivated(name, version) {
    var activatedVersion = getActivatedVersion(name);
    if (activatedVersion !== null) {
        if (version == undefined) {
            return true;
        }
        return activatedVersion == version;
    }
    return false;
}

function getInstalledVersions(name) {
    var list = fs.list(getInstallDir()).filter(function(dirName) {
        return dirName.substring(0, dirName.lastIndexOf("-")) == name;
    }).map(function(dirName) {
        return dirName.substring(dirName.lastIndexOf("-") + 1);
    });
    if (list.length > 1) {
        semver.sort(list, -1);
    }
    return list;
}

/**
 * Returns the latest installed version of the specified package
 * @param {String} name The package name
 * @returns The latest installed version of the package
 * @type String
 */
function getLatestInstalledVersion(name) {
    return getInstalledVersions(name)[0] || null;
}

function getLatestInstalledVersions() {
    var result = {};
    var list = fs.list(getInstallDir());
    for each (let dirName in list) {
        if (strings.startsWith(dirName, ".")) {
            continue;
        }
        var descriptor = getDescriptor(fs.join(getInstallDir(), dirName));
        if (descriptor === null) {
            continue;
        }
        if (!Object.hasOwnProperty(result, descriptor.name) ||
                !semver.isGreater(descriptor.version, result[descriptor.name])) {
            result[descriptor.name] = descriptor.version;
        }
    }
    return result;
}

function getActivatedVersion(name) {
    var link = fs.join(getPackagesDir(), name);
    if (fs.exists(link)) {
        var activePackage = getDescriptor(link);
        if (activePackage != null) {
            return activePackage.version;
        }
    }
    return null;
}

function getActivatedVersions() {
    var result = {};
    var list = fs.list(getPackagesDir());
    for each (let name in list) {
        var version = getActivatedVersion(name);
        if (version !== null) {
            result[name] = version;
        }
    }
    return result;
}

function getDescriptor(dir) {
    var jsonPath = fs.normal(fs.join(dir, "package.json"));
    if (fs.exists(jsonPath)) {
        return JSON.parse(fs.read(jsonPath));
    }
    return null;
}

function install(archivePath, name, version) {
    var installDir = getInstallDir(name, version);
    log.debug("Installing", fs.base(archivePath), "in", installDir);
    if (!fs.exists(installDir)) {
        fs.makeTree(installDir);
        var fileStream = fs.open(archivePath, {
            "binary": true
        });
        compress.extractStream(fileStream, installDir);
        // make all files in "bin" directory of installed package executable
        var binDir = fs.join(installDir, "bin");
        if (fs.exists(binDir)) {
            for each (var fileName in fs.list(binDir)) {
                var binFile = fs.join(binDir, fileName);
                log.debug("Changing permissions of", binFile, "to 0755");
                fs.changePermissions(binFile, 0755);
            }
        }
        log.debug("Installed", name, version, "in", installDir);
    }
    return installDir;
}

function uninstall(name, version) {
    var installDir = getInstallDir(name, version);
    if (!fs.exists(installDir)) {
        throw new Error("The package " + name + " " + version + " isn't installed")
    }
    fs.removeTree(installDir);
    log.debug("Uninstalled", name, version, "in", installDir);
    return installDir;
}

function activate(name, version) {
    if (os.isWindows()) {
        throw new Error("Package activation isn't supported on Windows. Please do it manually.");
    }
    var installDir = getInstallDir(name, version);
    var packagesDir = getPackagesDir();
    if (!fs.exists(installDir)) {
        throw new Error("The package " + name + " " + version + " isn't installed");
    }
    var src = fs.relative(packagesDir, installDir);
    var dest = fs.join(packagesDir, name);
    if (fs.exists(dest)) {
        if (!fs.isLink(dest)) {
            throw new Error("Package " + name +
                    " has been copied into packages directory, please move it away manually");
        } else if (!isManaged(dest)) {
            throw new Error(name + " wasn't installed by rp, please deactivate manually");
        }
        fs.removeDirectory(dest);
    }
    if (fs.symbolicLink(src, dest) < 0) {
        throw new Error("Unable to activate the package " + name);
    }
    log.debug("Activated", name, version, "in", packagesDir);
    return dest;
}

function deactivate(name) {
    if (os.isWindows()) {
        throw new Error("Package deactivation isn't supported on Windows. Please do it manually.");
    }
    var path = fs.normal(fs.join(getPackagesDir(), name));
    if (!fs.exists(path)) {
        throw new Error("The package " + name + " is not activated");
    } else if (!fs.isLink(path)) {
        throw new Error("Package " + name +
                " has been copied into packages directory, please move it away manually");
    } else if (!isManaged(path)) {
        throw new Error(name + " wasn't installed by rp, please deactivate manually");
    }
    // FIXME: remove() doesn't allow removing symlinks to directories
    fs.removeDirectory(path);
    log.debug("Deactivated", path);
    return;
}
<|endoftext|>


<commit_before>import expectPuppeteer from 'expect-puppeteer'

const timeout = 5000;

describe(
    'WAYF is showing connected IdPs by default',
    () => {
        let page;
        beforeAll(async () => {
            page = await global.__BROWSER__.newPage();
            const override = Object.assign(page.viewport(), {width: 1920, height: 1080});
            page.setViewport(override);
        }, timeout);

        it('Should show five connected IdPs and the search field', async () => {

            await page.goto('https://engine.vm.openconext.org/functional-testing/wayf');

            // Load the connected IdPs by selecting their h3 titles
            let idps = await page.evaluate(() => [...document.querySelectorAll('#connected-idp-picker h3')].map(elem => elem.innerText));
            expect(idps).toHaveLength(5);

            // Verify the IdP is set with a title
            expect(idps[2]).toEqual('Connected IdP 3');

            // Test the search option by filtering on IdP 4, should yield one search result
            await page.type('.mod-search-input', 'IdP 4');

            // Ensure we have the search field
            const searchFieldValue = await page.evaluate(() => document.querySelector('.mod-search-input').attributes.getNamedItem('placeholder').value);
            expect(searchFieldValue).toEqual('Search for an organisation...');

            // After filtering the search results, verify one result is visible
            idps = await page.evaluate(() => [...document.querySelectorAll('#connected-idp-picker h3')].map(elem => elem.innerText));
            expect(idps).toHaveLength(1);
            expect(idps[0]).toEqual('Connected IdP 4');

            // Ensure some elements are on the page
            await expectPuppeteer(page).toMatch('Select an organisation to login to the service');
            // Ensure some elements are NOT on the page
            await expectPuppeteer(page).not.toMatch('Identity providers without access');
            await expectPuppeteer(page).not.toMatch('Remember my choice');
            await expectPuppeteer(page).not.toMatch('Return to service provider');

            await page.screenshot({path: './material/javascripts/tests/smoke/screenshots/connected.png'});
        });

        it('Should show ten connected IdPs', async () => {
            await page.goto('https://engine.vm.openconext.org/functional-testing/wayf?connectedIdps=10');
            let idps = await page.evaluate(() => [...document.querySelectorAll('#connected-idp-picker h3')].map(elem => elem.innerText));
            expect(idps).toHaveLength(10);
            await page.screenshot({path: './material/javascripts/tests/smoke/screenshots/connected-10.png'});
        });

        it('Should show no connected IdPs when cutoff point is configured', async () => {
            await page.goto('https://engine.vm.openconext.org/functional-testing/wayf?connectedIdps=6&cutoffPointForShowingUnfilteredIdps=5');

            let idps = await page.evaluate(() => [...document.querySelectorAll('#connected-idp-picker h3')].map(elem => elem.innerText));
            expect(idps).toHaveLength(0);
            await page.screenshot({path: './material/javascripts/tests/smoke/screenshots/connected-cutoff-1.png'});

            await page.type('.mod-search-input', 'IdP');
            idps = await page.evaluate(() => [...document.querySelectorAll('#connected-idp-picker h3')].map(elem => elem.innerText));
            expect(idps).toHaveLength(6);
            await page.screenshot({path: './material/javascripts/tests/smoke/screenshots/connected-cutoff-2.png'});
        });

        it('Should show the return to service link when configured', async () => {
            await page.goto('https://engine.vm.openconext.org/functional-testing/wayf?connectedIdps=5&backLink=true');
            // Ensure some elements are on the page
            await expectPuppeteer(page).toMatch('Select an organisation to login to the service');
            await expectPuppeteer(page).toMatch('Return to service provider');
            // Ensure some elements are NOT on the page
            await expectPuppeteer(page).not.toMatch('Identity providers without access');
            await expectPuppeteer(page).not.toMatch('Remember my choice');

            // To be more precise, the links should be in the header and footer
            const headerLink = await expect(page).toMatchElement('.mod-header .comp-links li:nth-child(1) a');
            await expectPuppeteer(headerLink).toMatch('Return to service provider');

            const footerLink = await expect(page).toMatchElement('.footer-menu .comp-links li:nth-child(2) a');
            await expectPuppeteer(footerLink).toMatch('Return to service provider');

            await page.screenshot({path: './material/javascripts/tests/smoke/screenshots/connected-back-link.png'});
        });

        it('Should show the remember my choice option', async () => {
            await page.goto('https://engine.vm.openconext.org/functional-testing/wayf?connectedIdps=5&rememberChoiceFeature=true');
            // Ensure some elements are on the page
            await expectPuppeteer(page).toMatch('Select an organisation to login to the service');
            await expectPuppeteer(page).toMatch('Remember my choice');
            // Ensure some elements are NOT on the page
            await expectPuppeteer(page).not.toMatch('Identity providers without access');
            await expectPuppeteer(page).not.toMatch('Return to service provider');

            await page.screenshot({path: './material/javascripts/tests/smoke/screenshots/connected-remember-choice.png'});
        });
    },
    timeout,
);
<commit_msg>Translate expect-puppeteer back to regular asserts<commit_after>const timeout = 10000;

describe(
    'WAYF is showing connected IdPs by default',
    () => {
        let page;
        beforeAll(async () => {
            page = await global.__BROWSER__.newPage();
            const override = Object.assign(page.viewport(), {width: 1920, height: 1080});
            page.setViewport(override);
        }, timeout);

        it('Should show five connected IdPs and the search field', async () => {

            await page.goto('https://engine.vm.openconext.org/functional-testing/wayf');

            // Load the connected IdPs by selecting their h3 titles
            let idps = await page.evaluate(() => [...document.querySelectorAll('#idp-picker h3')].map(elem => elem.innerText));
            expect(idps).toHaveLength(5);

            // Verify the IdP is set with a title
            expect(idps[2]).toEqual('Connected IdP 3');

            // Test the search option by filtering on IdP 4, should yield one search result
            await page.type('.mod-search-input', 'IdP 4');

            // Ensure we have the search field
            const searchFieldValue = await page.evaluate(() => document.querySelector('.mod-search-input').attributes.getNamedItem('placeholder').value);
            expect(searchFieldValue).toEqual('Search for an organisation...');

            // After filtering the search results, verify one result is visible
            idps = await page.evaluate(() => [...document.querySelectorAll('#idp-picker h3')].map(elem => elem.innerText));
            expect(idps).toHaveLength(1);
            expect(idps[0]).toEqual('Connected IdP 4');

            const text = await page.evaluate(() => document.body.textContent);

            // Ensure some elements are on the page
            expect(text).toContain('Select an organisation to login to the service');
            // Ensure some elements are NOT on the page
            expect(text).toEqual(expect.not.stringContaining('Identity providers without access'));
            expect(text).toEqual(expect.not.stringContaining('Remember my choice'));
            expect(text).toEqual(expect.not.stringContaining('Return to service provider'));

            await page.screenshot({path: './material/javascripts/tests/smoke/screenshots/connected.png'});
        });

        it('Should show ten connected IdPs', async () => {
            await page.goto('https://engine.vm.openconext.org/functional-testing/wayf?connectedIdps=10');
            let idps = await page.evaluate(() => [...document.querySelectorAll('#idp-picker h3')].map(elem => elem.innerText));
            expect(idps).toHaveLength(10);
            await page.screenshot({path: './material/javascripts/tests/smoke/screenshots/connected-10.png'});
        });

        it('Should show no connected IdPs when cutoff point is configured', async () => {
            await page.goto('https://engine.vm.openconext.org/functional-testing/wayf?connectedIdps=6&cutoffPointForShowingUnfilteredIdps=5');

            let idps = await page.evaluate(() => [...document.querySelectorAll('#idp-picker h3')].map(elem => elem.innerText));
            expect(idps).toHaveLength(0);
            await page.screenshot({path: './material/javascripts/tests/smoke/screenshots/connected-cutoff-1.png'});

            await page.type('.mod-search-input', 'IdP');
            idps = await page.evaluate(() => [...document.querySelectorAll('#idp-picker h3')].map(elem => elem.innerText));
            expect(idps).toHaveLength(6);
            await page.screenshot({path: './material/javascripts/tests/smoke/screenshots/connected-cutoff-2.png'});
        });

        it('Should show the return to service link when configured', async () => {
            await page.goto('https://engine.vm.openconext.org/functional-testing/wayf?connectedIdps=5&backLink=true');

            const text = await page.evaluate(() => document.body.textContent);
            // Ensure some elements are on the page
            expect(text).toContain('Select an organisation to login to the service');
            expect(text).toContain('Return to service provider');
            // Ensure some elements are NOT on the page
            expect(text).toEqual(expect.not.stringContaining('Identity providers without access'));
            expect(text).toEqual(expect.not.stringContaining('Remember my choice'));

            // To be more precise, the links should be in the header and footer
            const headerLink = await page.evaluate(() => document.querySelector('.mod-header .comp-links li:nth-child(1) a').textContent);
            await expect(headerLink).toMatch('Return to service provider');

            const footerLink = await page.evaluate(() => document.querySelector('.footer-menu .comp-links li:nth-child(2) a').textContent);
            await expect(footerLink).toMatch('Return to service provider');

            await page.screenshot({path: './material/javascripts/tests/smoke/screenshots/connected-back-link.png'});
        });

        it('Should show the remember my choice option', async () => {
            await page.goto('https://engine.vm.openconext.org/functional-testing/wayf?connectedIdps=5&rememberChoiceFeature=true');

            const text = await page.evaluate(() => document.body.textContent);
            // Ensure some elements are on the page
            expect(text).toContain('Select an organisation to login to the service');
            expect(text).toContain('Remember my choice');
            // Ensure some elements are NOT on the page
            expect(text).toEqual(expect.not.stringContaining('Identity providers without access'));
            expect(text).toEqual(expect.not.stringContaining('Return to service provider'));

            await page.screenshot({path: './material/javascripts/tests/smoke/screenshots/connected-remember-choice.png'});
        });
    },
    timeout,
);
<|endoftext|>