<commit_before>/*
 *
 * Copyright 2013 Anis Kadri
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

/* jshint unused: vars */

var fs = require('fs');
var path = require('path');
var shell = require('shelljs');
var events = require('cordova-common').events;
var CordovaError = require('cordova-common').CordovaError;

var handlers = {
    'source-file': {
        install: function (obj, plugin, project, options) {
            if (!obj.src) throw new CordovaError(generateAttributeError('src', 'source-file', plugin.id));
            if (!obj.targetDir) throw new CordovaError(generateAttributeError('target-dir', 'source-file', plugin.id));

            var dest = path.join(obj.targetDir, path.basename(obj.src));

            if (options && options.android_studio === true) {
                dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
            }

            if (options && options.force) {
                copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
            } else {
                copyNewFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
            }
        },
        uninstall: function (obj, plugin, project, options) {
            var dest = path.join(obj.targetDir, path.basename(obj.src));

            if (options && options.android_studio === true) {
                dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
            }

            deleteJava(project.projectDir, dest);
        }
    },
    'lib-file': {
        install: function (obj, plugin, project, options) {
            var dest = path.join('libs', path.basename(obj.src));
            if (options && options.android_studio === true) {
                dest = path.join('app/libs', path.basename(obj.src));
            }
            copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
        },
        uninstall: function (obj, plugin, project, options) {
            var dest = path.join('libs', path.basename(obj.src));
            if (options && options.android_studio === true) {
                dest = path.join('app/libs', path.basename(obj.src));
            }
            removeFile(project.projectDir, dest);
        }
    },
    'resource-file': {
        install: function (obj, plugin, project, options) {
            copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), !!(options && options.link));
        },
        uninstall: function (obj, plugin, project, options) {
            removeFile(project.projectDir, path.normalize(obj.target));
        }
    },
    'framework': {
        install: function (obj, plugin, project, options) {
            var src = obj.src;
            if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));

            events.emit('verbose', 'Installing Android library: ' + src);
            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
            var subDir;

            if (obj.custom) {
                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
                copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, !!(options && options.link));
                subDir = path.resolve(project.projectDir, subRelativeDir);
            } else {
                obj.type = 'sys';
                subDir = src;
            }

            if (obj.type === 'gradleReference') {
                project.addGradleReference(parentDir, subDir);
            } else if (obj.type === 'sys') {
                project.addSystemLibrary(parentDir, subDir);
            } else {
                project.addSubProject(parentDir, subDir);
            }
        },
        uninstall: function (obj, plugin, project, options) {
            var src = obj.src;
            if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));

            events.emit('verbose', 'Uninstalling Android library: ' + src);
            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
            var subDir;

            if (obj.custom) {
                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
                removeFile(project.projectDir, subRelativeDir);
                subDir = path.resolve(project.projectDir, subRelativeDir);
                // If it's the last framework in the plugin, remove the parent directory.
                var parDir = path.dirname(subDir);
                if (fs.existsSync(parDir) && fs.readdirSync(parDir).length === 0) {
                    fs.rmdirSync(parDir);
                }
            } else {
                obj.type = 'sys';
                subDir = src;
            }

            if (obj.type === 'gradleReference') {
                project.removeGradleReference(parentDir, subDir);
            } else if (obj.type === 'sys') {
                project.removeSystemLibrary(parentDir, subDir);
            } else {
                project.removeSubProject(parentDir, subDir);
            }
        }
    },
    asset: {
        install: function (obj, plugin, project, options) {
            if (!obj.src) {
                throw new CordovaError(generateAttributeError('src', 'asset', plugin.id));
            }
            if (!obj.target) {
                throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));
            }

            copyFile(plugin.dir, obj.src, project.www, obj.target);
            if (options && options.usePlatformWww) {
                // CB-11022 copy file to both directories if usePlatformWww is specified
                copyFile(plugin.dir, obj.src, project.platformWww, obj.target);
            }
        },
        uninstall: function (obj, plugin, project, options) {
            var target = obj.target || obj.src;

            if (!target) throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));

            removeFileF(path.resolve(project.www, target));
            removeFileF(path.resolve(project.www, 'plugins', plugin.id));
            if (options && options.usePlatformWww) {
                // CB-11022 remove file from both directories if usePlatformWww is specified
                removeFileF(path.resolve(project.platformWww, target));
                removeFileF(path.resolve(project.platformWww, 'plugins', plugin.id));
            }
        }
    },
    'js-module': {
        install: function (obj, plugin, project, options) {
            // Copy the plugin's files into the www directory.
            var moduleSource = path.resolve(plugin.dir, obj.src);
            var moduleName = plugin.id + '.' + (obj.name || path.basename(obj.src, path.extname(obj.src)));

            // Read in the file, prepend the cordova.define, and write it back out.
            var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
            if (moduleSource.match(/.*\.json$/)) {
                scriptContent = 'module.exports = ' + scriptContent;
            }
            scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {\n' + scriptContent + '\n});\n';

            var wwwDest = path.resolve(project.www, 'plugins', plugin.id, obj.src);
            shell.mkdir('-p', path.dirname(wwwDest));
            fs.writeFileSync(wwwDest, scriptContent, 'utf-8');

            if (options && options.usePlatformWww) {
                // CB-11022 copy file to both directories if usePlatformWww is specified
                var platformWwwDest = path.resolve(project.platformWww, 'plugins', plugin.id, obj.src);
                shell.mkdir('-p', path.dirname(platformWwwDest));
                fs.writeFileSync(platformWwwDest, scriptContent, 'utf-8');
            }
        },
        uninstall: function (obj, plugin, project, options) {
            var pluginRelativePath = path.join('plugins', plugin.id, obj.src);
            removeFileAndParents(project.www, pluginRelativePath);
            if (options && options.usePlatformWww) {
                // CB-11022 remove file from both directories if usePlatformWww is specified
                removeFileAndParents(project.platformWww, pluginRelativePath);
            }
        }
    }
};

module.exports.getInstaller = function (type) {
    if (handlers[type] && handlers[type].install) {
        return handlers[type].install;
    }

    events.emit('verbose', '<' + type + '> is not supported for android plugins');
};

module.exports.getUninstaller = function (type) {
    if (handlers[type] && handlers[type].uninstall) {
        return handlers[type].uninstall;
    }

    events.emit('verbose', '<' + type + '> is not supported for android plugins');
};

function copyFile (plugin_dir, src, project_dir, dest, link) {
    src = path.resolve(plugin_dir, src);
    if (!fs.existsSync(src)) throw new CordovaError('"' + src + '" not found!');

    // check that src path is inside plugin directory
    var real_path = fs.realpathSync(src);
    var real_plugin_path = fs.realpathSync(plugin_dir);
    if (real_path.indexOf(real_plugin_path) !== 0) { throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"'); }

    dest = path.resolve(project_dir, dest);

    // check that dest path is located in project directory
    if (dest.indexOf(project_dir) !== 0) { throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project'); }

    shell.mkdir('-p', path.dirname(dest));
    if (link) {
        symlinkFileOrDirTree(src, dest);
    } else if (fs.statSync(src).isDirectory()) {
        // XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq
        shell.cp('-Rf', src + '/*', dest);
    } else {
        shell.cp('-f', src, dest);
    }
}

// Same as copy file but throws error if target exists
function copyNewFile (plugin_dir, src, project_dir, dest, link) {
    var target_path = path.resolve(project_dir, dest);
    if (fs.existsSync(target_path)) { throw new CordovaError('"' + target_path + '" already exists!'); }

    copyFile(plugin_dir, src, project_dir, dest, !!link);
}

function symlinkFileOrDirTree (src, dest) {
    if (fs.existsSync(dest)) {
        shell.rm('-Rf', dest);
    }

    if (fs.statSync(src).isDirectory()) {
        shell.mkdir('-p', dest);
        fs.readdirSync(src).forEach(function (entry) {
            symlinkFileOrDirTree(path.join(src, entry), path.join(dest, entry));
        });
    } else {
        fs.symlinkSync(path.relative(fs.realpathSync(path.dirname(dest)), src), dest);
    }
}

// checks if file exists and then deletes. Error if doesn't exist
function removeFile (project_dir, src) {
    var file = path.resolve(project_dir, src);
    shell.rm('-Rf', file);
}

// deletes file/directory without checking
function removeFileF (file) {
    shell.rm('-Rf', file);
}

// Sometimes we want to remove some java, and prune any unnecessary empty directories
function deleteJava (project_dir, destFile) {
    removeFileAndParents(project_dir, destFile, 'src');
}

function removeFileAndParents (baseDir, destFile, stopper) {
    stopper = stopper || '.';
    var file = path.resolve(baseDir, destFile);
    if (!fs.existsSync(file)) return;

    removeFileF(file);

    // check if directory is empty
    var curDir = path.dirname(file);

    while (curDir !== path.resolve(baseDir, stopper)) {
        if (fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
            fs.rmdirSync(curDir);
            curDir = path.resolve(curDir, '..');
        } else {
            // directory not empty...do nothing
            break;
        }
    }
}

function generateAttributeError (attribute, element, id) {
    return 'Required attribute "' + attribute + '" not specified in <' + element + '> element from plugin: ' + id;
}
<commit_msg>CB-11244: Added remapping for drawables<commit_after>/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

/* jshint unused: vars */

var fs = require('fs');
var path = require('path');
var shell = require('shelljs');
var events = require('cordova-common').events;
var CordovaError = require('cordova-common').CordovaError;

var handlers = {
    'source-file': {
        install: function (obj, plugin, project, options) {
            if (!obj.src) throw new CordovaError(generateAttributeError('src', 'source-file', plugin.id));
            if (!obj.targetDir) throw new CordovaError(generateAttributeError('target-dir', 'source-file', plugin.id));

            var dest = path.join(obj.targetDir, path.basename(obj.src));

            if (options && options.android_studio === true) {
                dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
            }

            if (options && options.force) {
                copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
            } else {
                copyNewFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
            }
        },
        uninstall: function (obj, plugin, project, options) {
            var dest = path.join(obj.targetDir, path.basename(obj.src));

            if (options && options.android_studio === true) {
                dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
            }

            deleteJava(project.projectDir, dest);
        }
    },
    'lib-file': {
        install: function (obj, plugin, project, options) {
            var dest = path.join('libs', path.basename(obj.src));
            if (options && options.android_studio === true) {
                dest = path.join('app/libs', path.basename(obj.src));
            }
            copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
        },
        uninstall: function (obj, plugin, project, options) {
            var dest = path.join('libs', path.basename(obj.src));
            if (options && options.android_studio === true) {
                dest = path.join('app/libs', path.basename(obj.src));
            }
            removeFile(project.projectDir, dest);
        }
    },
    'resource-file': {
        install: function (obj, plugin, project, options) {
            var dest = path.join('app/src/main', path.normalize(obj.target));
            copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
        },
        uninstall: function (obj, plugin, project, options) {
            var dest = path.join('app/src/main', path.normalize(obj.target));
            removeFile(dest, path.normalize(obj.target));
        }
    },
    'framework': {
        install: function (obj, plugin, project, options) {
            var src = obj.src;
            if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));

            events.emit('verbose', 'Installing Android library: ' + src);
            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
            var subDir;

            if (obj.custom) {
                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
                copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, !!(options && options.link));
                subDir = path.resolve(project.projectDir, subRelativeDir);
            } else {
                obj.type = 'sys';
                subDir = src;
            }

            if (obj.type === 'gradleReference') {
                project.addGradleReference(parentDir, subDir);
            } else if (obj.type === 'sys') {
                project.addSystemLibrary(parentDir, subDir);
            } else {
                project.addSubProject(parentDir, subDir);
            }
        },
        uninstall: function (obj, plugin, project, options) {
            var src = obj.src;
            if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));

            events.emit('verbose', 'Uninstalling Android library: ' + src);
            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
            var subDir;

            if (obj.custom) {
                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
                removeFile(project.projectDir, subRelativeDir);
                subDir = path.resolve(project.projectDir, subRelativeDir);
                // If it's the last framework in the plugin, remove the parent directory.
                var parDir = path.dirname(subDir);
                if (fs.existsSync(parDir) && fs.readdirSync(parDir).length === 0) {
                    fs.rmdirSync(parDir);
                }
            } else {
                obj.type = 'sys';
                subDir = src;
            }

            if (obj.type === 'gradleReference') {
                project.removeGradleReference(parentDir, subDir);
            } else if (obj.type === 'sys') {
                project.removeSystemLibrary(parentDir, subDir);
            } else {
                project.removeSubProject(parentDir, subDir);
            }
        }
    },
    asset: {
        install: function (obj, plugin, project, options) {
            if (!obj.src) {
                throw new CordovaError(generateAttributeError('src', 'asset', plugin.id));
            }
            if (!obj.target) {
                throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));
            }

            copyFile(plugin.dir, obj.src, project.www, obj.target);
            if (options && options.usePlatformWww) {
                // CB-11022 copy file to both directories if usePlatformWww is specified
                copyFile(plugin.dir, obj.src, project.platformWww, obj.target);
            }
        },
        uninstall: function (obj, plugin, project, options) {
            var target = obj.target || obj.src;

            if (!target) throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));

            removeFileF(path.resolve(project.www, target));
            removeFileF(path.resolve(project.www, 'plugins', plugin.id));
            if (options && options.usePlatformWww) {
                // CB-11022 remove file from both directories if usePlatformWww is specified
                removeFileF(path.resolve(project.platformWww, target));
                removeFileF(path.resolve(project.platformWww, 'plugins', plugin.id));
            }
        }
    },
    'js-module': {
        install: function (obj, plugin, project, options) {
            // Copy the plugin's files into the www directory.
            var moduleSource = path.resolve(plugin.dir, obj.src);
            var moduleName = plugin.id + '.' + (obj.name || path.basename(obj.src, path.extname(obj.src)));

            // Read in the file, prepend the cordova.define, and write it back out.
            var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
            if (moduleSource.match(/.*\.json$/)) {
                scriptContent = 'module.exports = ' + scriptContent;
            }
            scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {\n' + scriptContent + '\n});\n';

            var wwwDest = path.resolve(project.www, 'plugins', plugin.id, obj.src);
            shell.mkdir('-p', path.dirname(wwwDest));
            fs.writeFileSync(wwwDest, scriptContent, 'utf-8');

            if (options && options.usePlatformWww) {
                // CB-11022 copy file to both directories if usePlatformWww is specified
                var platformWwwDest = path.resolve(project.platformWww, 'plugins', plugin.id, obj.src);
                shell.mkdir('-p', path.dirname(platformWwwDest));
                fs.writeFileSync(platformWwwDest, scriptContent, 'utf-8');
            }
        },
        uninstall: function (obj, plugin, project, options) {
            var pluginRelativePath = path.join('plugins', plugin.id, obj.src);
            removeFileAndParents(project.www, pluginRelativePath);
            if (options && options.usePlatformWww) {
                // CB-11022 remove file from both directories if usePlatformWww is specified
                removeFileAndParents(project.platformWww, pluginRelativePath);
            }
        }
    }
};

module.exports.getInstaller = function (type) {
    if (handlers[type] && handlers[type].install) {
        return handlers[type].install;
    }

    events.emit('verbose', '<' + type + '> is not supported for android plugins');
};

module.exports.getUninstaller = function (type) {
    if (handlers[type] && handlers[type].uninstall) {
        return handlers[type].uninstall;
    }

    events.emit('verbose', '<' + type + '> is not supported for android plugins');
};

function copyFile (plugin_dir, src, project_dir, dest, link) {
    src = path.resolve(plugin_dir, src);
    if (!fs.existsSync(src)) throw new CordovaError('"' + src + '" not found!');

    // check that src path is inside plugin directory
    var real_path = fs.realpathSync(src);
    var real_plugin_path = fs.realpathSync(plugin_dir);
    if (real_path.indexOf(real_plugin_path) !== 0) { throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"'); }

    dest = path.resolve(project_dir, dest);

    // check that dest path is located in project directory
    if (dest.indexOf(project_dir) !== 0) { throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project'); }

    shell.mkdir('-p', path.dirname(dest));
    if (link) {
        symlinkFileOrDirTree(src, dest);
    } else if (fs.statSync(src).isDirectory()) {
        // XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq
        shell.cp('-Rf', src + '/*', dest);
    } else {
        shell.cp('-f', src, dest);
    }
}

// Same as copy file but throws error if target exists
function copyNewFile (plugin_dir, src, project_dir, dest, link) {
    var target_path = path.resolve(project_dir, dest);
    if (fs.existsSync(target_path)) { throw new CordovaError('"' + target_path + '" already exists!'); }

    copyFile(plugin_dir, src, project_dir, dest, !!link);
}

function symlinkFileOrDirTree (src, dest) {
    if (fs.existsSync(dest)) {
        shell.rm('-Rf', dest);
    }

    if (fs.statSync(src).isDirectory()) {
        shell.mkdir('-p', dest);
        fs.readdirSync(src).forEach(function (entry) {
            symlinkFileOrDirTree(path.join(src, entry), path.join(dest, entry));
        });
    } else {
        fs.symlinkSync(path.relative(fs.realpathSync(path.dirname(dest)), src), dest);
    }
}

// checks if file exists and then deletes. Error if doesn't exist
function removeFile (project_dir, src) {
    var file = path.resolve(project_dir, src);
    shell.rm('-Rf', file);
}

// deletes file/directory without checking
function removeFileF (file) {
    shell.rm('-Rf', file);
}

// Sometimes we want to remove some java, and prune any unnecessary empty directories
function deleteJava (project_dir, destFile) {
    removeFileAndParents(project_dir, destFile, 'src');
}

function removeFileAndParents (baseDir, destFile, stopper) {
    stopper = stopper || '.';
    var file = path.resolve(baseDir, destFile);
    if (!fs.existsSync(file)) return;

    removeFileF(file);

    // check if directory is empty
    var curDir = path.dirname(file);

    while (curDir !== path.resolve(baseDir, stopper)) {
        if (fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
            fs.rmdirSync(curDir);
            curDir = path.resolve(curDir, '..');
        } else {
            // directory not empty...do nothing
            break;
        }
    }
}

function generateAttributeError (attribute, element, id) {
    return 'Required attribute "' + attribute + '" not specified in <' + element + '> element from plugin: ' + id;
}
<|endoftext|>


<commit_before>import path from 'path';

Cypress.Commands.add('verifyOptions', () => {
  // Va facilities have services available
  cy.get('#facility-type-dropdown').select('VA health');
  cy.get('#service-type-dropdown').should('not.have.attr', 'disabled');
  cy.get('#facility-type-dropdown').select('Urgent care');
  cy.get('#service-type-dropdown').should('not.have.attr', 'disabled');
  cy.get('#facility-type-dropdown').select('VA benefits');
  cy.get('#service-type-dropdown').should('not.have.attr', 'disabled');

  // Va facilities don't have services available
  cy.get('#facility-type-dropdown').select('Vet Centers');
  cy.get('#service-type-dropdown').should('not.have', 'disabled');
  cy.get('#facility-type-dropdown').select('VA cemeteries');
  cy.get('#service-type-dropdown').should('not.have', 'disabled');

  // CCP care have services available
  cy.get('#facility-type-dropdown').select(
    'Community providers (in VA’s network)',
  );
  cy.get('#service-type-dropdown').should('not.have.attr', 'disabled');

  // CCP pharmacies dont have services available
  cy.get('#facility-type-dropdown').select(
    'Community pharmacies (in VA’s network)',
  );
  cy.get('#service-type-dropdown').should('not.have', 'disabled');
});

describe.skip('Facility search', () => {
  before(() => {
    cy.syncFixtures({
      constants: path.join(__dirname, '..', '..', 'constants'),
    });
  });

  beforeEach(() => {
    cy.server();
    cy.route('GET', '/v0/feature_toggles?*', []);
    cy.route('GET', '/v0/maintenance_windows', []);
    cy.route(
      'GET',
      '/v1/facilities/va?*',
      'fx:constants/mock-facility-data-v1',
    ).as('searchFacilities');
    cy.route('GET', '/geocoding/**/*', 'fx:constants/mock-geocoding-data');
  });

  it('does a simple search and finds a result on the list', () => {
    cy.visit('/find-locations');

    cy.injectAxe();
    cy.axeCheck();

    cy.verifyOptions();

    cy.get('#street-city-state-zip').type('Austin, TX');
    cy.get('#facility-type-dropdown').select('VA health');
    cy.get('#service-type-dropdown').select('Primary care');
    cy.get('#facility-search').click();
    cy.get('#search-results-subheader').contains(
      'Results for "VA health", "Primary care" near "Austin, Texas"',
    );
    cy.get('.facility-result a').should('exist');
    cy.get('.i-pin-card-map').contains('A');
    cy.get('.i-pin-card-map').contains('B');
    cy.get('.i-pin-card-map').contains('C');
    cy.get('.i-pin-card-map').contains('D');

    cy.get('.va-pagination').should('exist');
    cy.get('#other-tools').should('exist');
  });

  it.skip('should render breadcrumbs ', () => {
    cy.visit('/find-locations');

    cy.get('#street-city-state-zip').type('Austin, TX');
    cy.get('#facility-type-dropdown').select('VA health');
    cy.get('#facility-search')
      .click()
      .then(() => {
        cy.injectAxe();
        cy.axeCheck();

        cy.get('.facility-result a').should('exist');
        cy.route(
          'GET',
          '/v1/facilities/va/vha_674BY',
          'fx:constants/mock-facility-v1',
        ).as('fetchFacility');

        cy.findByText(/austin va clinic/i, { selector: 'a' })
          .first()
          .click()
          .then(() => {
            cy.axeCheck();

            cy.get('.all-details', { timeout: 10000 }).should('exist');

            cy.get('a[aria-current="page"').should('exist');

            cy.get(
              '.va-nav-breadcrumbs-list li:nth-of-type(3) a[aria-current="page"]',
            ).should('exist');

            cy.get(
              '.va-nav-breadcrumbs-list li:nth-of-type(3) a[aria-current="page"]',
            ).contains('Facility Details');

            cy.get('.va-nav-breadcrumbs-list li:nth-of-type(2) a').click();

            // Mobile View
            cy.viewport(375, 667);

            cy.get('.va-nav-breadcrumbs-list').should('exist');

            cy.get('.va-nav-breadcrumbs-list li:not(:nth-last-child(2))')
              .should('have.css', 'display')
              .and('match', /none/);

            cy.get('.va-nav-breadcrumbs-list li:nth-last-child(2)').contains(
              'Home',
            );
          });
      });
  });

  it('does not show search result header if no results are found', () => {
    cy.visit('/find-locations?fail=true');

    cy.get('#search-results-subheader').should('not.exist');
    cy.get('#other-tools').should('not.exist');
  });

  it('finds community dentists', () => {
    cy.visit('/find-locations');

    cy.get('#street-city-state-zip').type('Austin, TX');
    cy.get('#facility-type-dropdown').select(
      'Community providers (in VA’s network)',
    );
    cy.get('#service-type-ahead-input').type('Dentist');
    cy.get('#downshift-1-item-0').click();

    cy.get('#facility-search').click();
    cy.get('#search-results-subheader').contains(
      'Results for "Community providers (in VA’s network)", "Dentist - Orofacial Pain " near "Austin, Texas"',
    );
    cy.get('#other-tools').should('exist');

    cy.injectAxe();
    cy.axeCheck();

    cy.get('.facility-result h3').contains('BADEA, LUANA');

    cy.get('.va-pagination').should('not.exist');
  });

  it('finds community urgent care', () => {
    cy.visit('/find-locations');

    cy.get('#street-city-state-zip').type('Austin, TX');
    cy.get('#facility-type-dropdown').select(
      'Community providers (in VA’s network)',
    );
    cy.get('#service-type-ahead-input').type('Clinic/Center - Urgent care');
    cy.get('#downshift-1-item-0').click();

    cy.get('#facility-search').click();
    cy.get('#search-results-subheader').contains(
      'Results for "Community providers (in VA’s network)", "Clinic/Center - Urgent Care" near "Austin, Texas"',
    );
    cy.get('#other-tools').should('exist');

    cy.injectAxe();
    cy.axeCheck();

    cy.get('.facility-result h3').contains('Concentra Urgent Care');
    cy.get('.va-pagination').should('not.exist');
  });

  it('finds community urgent care', () => {
    cy.visit('/find-locations');

    cy.get('#street-city-state-zip').type('Austin, TX');
    cy.get('#facility-type-dropdown').select('Urgent care');
    cy.get('#service-type-dropdown').select(
      'Community urgent care providers (in VA’s network)',
    );
    cy.get('#facility-search').click();
    cy.get('#search-results-subheader').contains(
      'Results for "Urgent care", "Community urgent care providers (in VA’s network)" near "Austin, Texas"',
    );
    cy.get('#other-tools').should('exist');

    cy.injectAxe();
    cy.axeCheck();

    cy.get('.facility-result h3').contains('MinuteClinic');
    cy.get('.va-pagination').should('not.exist');
  });

  it('should recover search from an error response state - invalid input location', () => {
    cy.visit('/find-locations');
    cy.injectAxe();

    // Invalid location search
    cy.route('GET', '/geocoding/**/*', 'fx:constants/mock-failed-location').as(
      'failedLocation',
    );

    cy.get('#street-city-state-zip').type('31234asd0o203o213');
    cy.get('#facility-type-dropdown').select('VA health');
    cy.get('#facility-search').click();
    cy.get('.facility-search-results').contains(
      /Something’s not quite right. Please enter a valid or different location and try your search again./gi,
    );
    cy.axeCheck();

    // Valid location search
    cy.route('GET', '/geocoding/**/*', 'fx:constants/mock-geocoding-data').as(
      'validLocationSearch',
    );
    cy.get('#street-city-state-zip').type('Austin, TX');
    cy.get('#facility-type-dropdown').select('VA health');
    cy.get('#service-type-dropdown').select('Primary care');
    cy.get('#facility-search').click();
    cy.get('#search-results-subheader').contains(
      'Results for "VA health", "Primary care" near "Austin, Texas"',
    );
    cy.get('.facility-result a').should('exist');
    cy.axeCheck();
  });

  it('finds va benefits facility in Los Angeles and views its page', () => {
    cy.route('GET', '/geocoding/**/*', 'fx:constants/mock-la-location').as(
      'caLocation',
    );

    cy.visit('/find-locations');
    cy.injectAxe();

    cy.get('#street-city-state-zip').type('Los Angeles');
    cy.get('#facility-type-dropdown').select('VA benefits');
    cy.get('#facility-search').click();
    cy.get('#search-results-subheader').contains(
      'Results for "VA benefits", "All VA benefit services" near "Los Angeles, California"',
    );
    cy.get('#other-tools').should('exist');

    cy.axeCheck();

    cy.get('.facility-result a').contains('Los Angeles Ambulatory Care Center');
    cy.findByText(/Los Angeles Ambulatory Care Center/i, { selector: 'a' })
      .first()
      .click();
    cy.get('h1').contains('Los Angeles Ambulatory Care Center');
    cy.get('.p1')
      .first()
      .should('exist');
    cy.get('.facility-phone-group').should('exist');
    cy.findByText(/Get Directions/i).should('exist');
    cy.get('[alt="Static map"]').should('exist');
    cy.get('#hours-op h3').contains('Hours of operation');
    cy.get('#other-tools').should('not.exist');

    cy.axeCheck();
  });

  it('renders static map images on detail page', () => {
    // from https://stackoverflow.com/questions/51246606/test-loading-of-image-in-cypress
    cy.visit('/find-locations/facility/vha_688GA');
    cy.get('[alt="Static map"]')
      .should('be.visible')
      .and($img => {
        // "naturalWidth" and "naturalHeight" are set when the image loads
        expect($img[0].naturalWidth).to.be.greaterThan(0);
      });
  });
});
<commit_msg>Enable failing Facility Locator search E2E test on CircleCI (#15843)<commit_after>import path from 'path';

Cypress.Commands.add('verifyOptions', () => {
  // Va facilities have services available
  cy.get('#facility-type-dropdown').select('VA health');
  cy.get('#service-type-dropdown').should('not.have.attr', 'disabled');
  cy.get('#facility-type-dropdown').select('Urgent care');
  cy.get('#service-type-dropdown').should('not.have.attr', 'disabled');
  cy.get('#facility-type-dropdown').select('VA benefits');
  cy.get('#service-type-dropdown').should('not.have.attr', 'disabled');

  // Va facilities don't have services available
  cy.get('#facility-type-dropdown').select('Vet Centers');
  cy.get('#service-type-dropdown').should('not.have', 'disabled');
  cy.get('#facility-type-dropdown').select('VA cemeteries');
  cy.get('#service-type-dropdown').should('not.have', 'disabled');

  // CCP care have services available
  cy.get('#facility-type-dropdown').select(
    'Community providers (in VA’s network)',
  );
  cy.get('#service-typeahead').should('not.have.attr', 'disabled');

  // CCP pharmacies dont have services available
  cy.get('#facility-type-dropdown').select(
    'Community pharmacies (in VA’s network)',
  );
  cy.get('#service-typeahead').should('not.have', 'disabled');
});

describe('Facility search', () => {
  before(function() {
    if (!Cypress.env('CIRCLECI')) this.skip();
    cy.syncFixtures({
      constants: path.join(__dirname, '..', '..', 'constants'),
    });
  });

  beforeEach(() => {
    cy.server();
    cy.route('GET', '/v0/feature_toggles?*', []);
    cy.route('GET', '/v0/maintenance_windows', []);
    cy.route(
      'GET',
      '/v1/facilities/va?*',
      'fx:constants/mock-facility-data-v1',
    ).as('searchFacilities');
    cy.route('GET', '/geocoding/**/*', 'fx:constants/mock-geocoding-data');
  });

  it('does a simple search and finds a result on the list', () => {
    cy.visit('/find-locations');

    cy.injectAxe();
    cy.axeCheck();

    cy.verifyOptions();

    cy.get('#street-city-state-zip').type('Austin, TX');
    cy.get('#facility-type-dropdown').select('VA health');
    cy.get('#service-type-dropdown').select('Primary care');
    cy.get('#facility-search').click();
    cy.get('#search-results-subheader').contains(
      'Results for "VA health", "Primary care" near "Austin, Texas"',
    );
    cy.get('.facility-result a').should('exist');
    cy.get('.i-pin-card-map').contains('A');
    cy.get('.i-pin-card-map').contains('B');
    cy.get('.i-pin-card-map').contains('C');
    cy.get('.i-pin-card-map').contains('D');

    cy.get('.va-pagination').should('exist');
    cy.get('#other-tools').should('exist');
  });

  it.skip('should render breadcrumbs ', () => {
    cy.visit('/find-locations');

    cy.get('#street-city-state-zip').type('Austin, TX');
    cy.get('#facility-type-dropdown').select('VA health');
    cy.get('#facility-search')
      .click()
      .then(() => {
        cy.injectAxe();
        cy.axeCheck();

        cy.get('.facility-result a').should('exist');
        cy.route(
          'GET',
          '/v1/facilities/va/vha_674BY',
          'fx:constants/mock-facility-v1',
        ).as('fetchFacility');

        cy.findByText(/austin va clinic/i, { selector: 'a' })
          .first()
          .click()
          .then(() => {
            cy.axeCheck();

            cy.get('.all-details', { timeout: 10000 }).should('exist');

            cy.get('a[aria-current="page"').should('exist');

            cy.get(
              '.va-nav-breadcrumbs-list li:nth-of-type(3) a[aria-current="page"]',
            ).should('exist');

            cy.get(
              '.va-nav-breadcrumbs-list li:nth-of-type(3) a[aria-current="page"]',
            ).contains('Facility Details');

            cy.get('.va-nav-breadcrumbs-list li:nth-of-type(2) a').click();

            // Mobile View
            cy.viewport(375, 667);

            cy.get('.va-nav-breadcrumbs-list').should('exist');

            cy.get('.va-nav-breadcrumbs-list li:not(:nth-last-child(2))')
              .should('have.css', 'display')
              .and('match', /none/);

            cy.get('.va-nav-breadcrumbs-list li:nth-last-child(2)').contains(
              'Home',
            );
          });
      });
  });

  it('does not show search result header if no results are found', () => {
    cy.visit('/find-locations?fail=true');

    cy.get('#search-results-subheader').should('not.exist');
    cy.get('#other-tools').should('not.exist');
  });

  it('finds community dentists', () => {
    cy.visit('/find-locations');
    cy.injectAxe();

    cy.get('#street-city-state-zip').type('Austin, TX');
    cy.get('#facility-type-dropdown').select(
      'Community providers (in VA’s network)',
    );
    cy.get('#service-type-ahead-input').type('Dentist');
    cy.get('#downshift-1-item-0').click();

    cy.get('#facility-search').click();
    cy.get('#search-results-subheader').contains(
      'Results for "Community providers (in VA’s network)", "Dentist - Orofacial Pain " near "Austin, Texas"',
    );
    cy.get('#other-tools').should('exist');

    cy.axeCheck();

    cy.get('.facility-result h3').contains('BADEA, LUANA');

    cy.get('.va-pagination').should('not.exist');
  });

  it('finds community urgent care', () => {
    cy.visit('/find-locations');
    cy.injectAxe();

    cy.get('#street-city-state-zip').type('Austin, TX');
    cy.get('#facility-type-dropdown').select(
      'Community providers (in VA’s network)',
    );
    cy.get('#service-type-ahead-input').type('Clinic/Center - Urgent Care');
    cy.get('#downshift-1-item-0').click();

    cy.get('#facility-search').click();
    cy.get('#search-results-subheader').contains(
      'Results for "Community providers (in VA’s network)", "Clinic/Center - Urgent Care" near "Austin, Texas"',
    );
    cy.get('#other-tools').should('exist');

    cy.axeCheck();

    cy.get('.facility-result h3').contains('Concentra Urgent Care');
    cy.get('.va-pagination').should('not.exist');
  });

  it('finds community urgent care', () => {
    cy.visit('/find-locations');

    cy.get('#street-city-state-zip').type('Austin, TX');
    cy.get('#facility-type-dropdown').select('Urgent care');
    cy.get('#service-type-dropdown').select(
      'Community urgent care providers (in VA’s network)',
    );
    cy.get('#facility-search').click();
    cy.get('#search-results-subheader').contains(
      'Results for "Urgent care", "Community urgent care providers (in VA’s network)" near "Austin, Texas"',
    );
    cy.get('#other-tools').should('exist');

    cy.injectAxe();
    cy.axeCheck();

    cy.get('.facility-result h3').contains('MinuteClinic');
    cy.get('.va-pagination').should('not.exist');
  });

  it('should recover search from an error response state - invalid input location', () => {
    cy.visit('/find-locations');
    cy.injectAxe();

    // Invalid location search
    cy.route(
      'GET',
      '/geocoding/**/*',
      'fx:constants/mock-failed-location',
      'failedLocation',
    );

    cy.get('#street-city-state-zip').type('31234asd0o203o213');
    cy.get('#facility-type-dropdown').select('VA health');
    cy.get('#facility-search').click();
    cy.get('.facility-search-results').contains(
      /Something’s not quite right. Please enter a valid or different location and try your search again./gi,
    );
    cy.axeCheck();

    // Valid location search
    cy.route('GET', '/geocoding/**/*', 'fx:constants/mock-geocoding-data').as(
      'validLocationSearch',
    );
    cy.get('#street-city-state-zip').clear();
    cy.get('#street-city-state-zip').type('Austin, TX');
    cy.get('#facility-type-dropdown').select('VA health');
    cy.get('#service-type-dropdown').select('Primary care');
    cy.get('#facility-search').click();
    cy.get('#search-results-subheader').contains(
      'Results for "VA health", "Primary care" near "Austin, Texas"',
    );
    cy.get('.facility-result a').should('exist');
    cy.axeCheck();
  });

  it('finds va benefits facility in Los Angeles and views its page', () => {
    cy.route('GET', '/geocoding/**/*', 'fx:constants/mock-la-location').as(
      'caLocation',
    );

    cy.visit('/find-locations');
    cy.injectAxe();

    cy.get('#street-city-state-zip').type('Los Angeles');
    cy.get('#facility-type-dropdown').select('VA benefits');
    cy.get('#facility-search').click();
    cy.get('#search-results-subheader').contains(
      'Results for "VA benefits", "All VA benefit services" near "Los Angeles, California"',
    );
    cy.get('#other-tools').should('exist');

    cy.axeCheck();

    cy.get('.facility-result a').contains('Los Angeles Ambulatory Care Center');
    cy.findByText(/Los Angeles Ambulatory Care Center/i, { selector: 'a' })
      .first()
      .click();
    cy.get('h1').contains('Los Angeles Ambulatory Care Center');
    cy.get('.p1')
      .first()
      .should('exist');
    cy.get('.facility-phone-group').should('exist');
    cy.findByText(/Get Directions/i).should('exist');
    cy.get('[alt="Static map"]').should('exist');
    cy.get('#hours-op h3').contains('Hours of operation');
    cy.get('#other-tools').should('not.exist');

    cy.axeCheck();
  });

  it('renders static map images on detail page', () => {
    // from https://stackoverflow.com/questions/51246606/test-loading-of-image-in-cypress
    cy.visit('/find-locations/facility/vha_688GA');
    cy.get('[alt="Static map"]')
      .should('be.visible')
      .and($img => {
        // "naturalWidth" and "naturalHeight" are set when the image loads
        expect($img[0].naturalWidth).to.be.greaterThan(0);
      });
  });
});
<|endoftext|>


<commit_before>'use strict';

/**
 * base class for controllers
 */
const path = require('path');
class baseController{

    /**
     *
     * @param req  : Object | HttpRequest
     * @param res  : Object | HttpResponse
     * @param next : Function | next middleware
     */
    constructor(req, res, next){

        this.debug = false;

        this.req = req;
        this.next = next;
        this.failedAuth = false;
        this.res = res;
        this.fs = require('fs');
        this.params = this.req.params;
        this.passport = require('passport');
        this.authViews = { user : [], admin : [] };
        this.models = {};
        this.viewDir = '';

        // autoload currentModel
        this.model = this.getModel(this.params.model);

        this.viewVars = {url : req.url, user: req.user, helpers: {}};
        this.viewVars.flashMessages =  this.req.session.flashMessages || [];
        this.helpersDir = '../views/helpers/';
    }

    /**
     * send Mail using template
     *
     * @param view : String | email view
     * @param data : Object | may contain context vars and layout
     * @param callback
     */
    sendMailView(view, data, callback){

        // Set default layout if not
        data.layout = data.layout || 'emailLayout';

        // render template before send email
        this.req.app.render(view, data, function(err, hbsTemplate){

            let mailOptions = {
                from: data.from,
                to: data.target,
                subject: data.subject,
                text: data.message,
                html: hbsTemplate
            };

            // send mail with defined transport object
            mailTransporter.sendMail(mailOptions, callback);
        });

    }

    /**
     * Check if action is authorised
     * @param view
     * @param user
     */
    isAuthorized(view, user){

        let role = user ? user.role : null;

        Object.keys(this.authViews).forEach((key) => {
            if(~this.authViews[key].indexOf(view)){
                if(role !== key ){

                    this.viewVars.flashMessages.push({
                        type: 'danger',
                        message: 'Droits insuffisants pour accéder à la page demandée!'
                    });

                    this.failedAuth = true;
                }
            }

        });
    }

    /**
     * Do things before any actions
     * @returns {string|*}
     */
    beforeAction(){

        let action = this.req.params.action;
        let user = this.req.user;
        this.isAuthorized(action, user);

    }

    /**
     * Do things before render
     * @param view
     * @param data
     * @returns {string|*}
     */
    beforeRender(view, data){

        if(view){
            this.params.action = view;
        }

        if(data){
            this.viewVars = Object.assign(this.viewVars, data);
        }

        // LOG
        if(this.debug){
            console.log('[method] : ', this.req.method);
            console.log('[viewDir] : "' , this.viewDir,'", [action] "', this.params.action, '"');
            console.log('==================== [viewVars] ====================== ' );
            console.dir( this.viewVars, {showHidden : false, depth : 1, color : true});
        }

        this.view = path.join(this.viewDir , this.params.action);

        return this.view;
    }

    /**
     * get model based on model name in lowercase
     * @param modelName
     * @returns {*}
     */
    getModel(modelName){

        modelName = baseController.toModelName(modelName);
        let modelPath = path.join('..','models', modelName);
        if(!this.models[modelName]){
            try{
                let model = require(modelPath);
                model.controller = this;
                this.models[modelName] = model;
            }catch(e){
                return null;
            }
        }

        return this.models[modelName];
    }

    /**
     * Capitalize modelname
     * @param model
     * @returns {string}
     */
    static toModelName(model){
        return model.charAt(0).toUpperCase() + model.slice(1);
    }

    /**
     * Call self::beforeRender then render view
     * @param view : string | template of the view to render
     * @param data
     * @param render
     */
    render(view, data, render){

        this.beforeRender(view, data, render);

        switch(render){
            case 'json' :
                this.res.json(data);
                break;
            default :
                this.res.render(this.view , this.viewVars, (err, template) =>{
                    if(err){
                        this.res.statusCode = 500;
                        this.next(err);
                    }else{
                        this.res.send(template);
                        this.next();
                    }
                });

                this.next();

                break;
        }
    }

    /**
     * Check if action exist
     * @param name
     * @returns {boolean}
     */
    actionExists(name){
        return name in this && typeof this[name] === 'function';
    }

    /**
     * Check if action exist and call it
     * @param name
     * @returns {boolean}
     */
    callAction(name){
        this.beforeAction();
        name = name + 'Action';
        if(this.actionExists(name)){
            // Auth requirement failed then redirect
            if(this.failedAuth){
                this.res.redirect('/');
                return true;
            }else{
                // TODO maybe return T/False from this.render in controller action
                // can be useful here
                this[name](this.params.arg);
                return true;
            }
        }else{
            return false;
        }
    }
}

module.exports = baseController;<commit_msg>fixed next in render baseController<commit_after>'use strict';

/**
 * base class for controllers
 */
const path = require('path');
class baseController{

    /**
     *
     * @param req  : Object | HttpRequest
     * @param res  : Object | HttpResponse
     * @param next : Function | next middleware
     */
    constructor(req, res, next){

        this.debug = false;

        this.req = req;
        this.next = next;
        this.failedAuth = false;
        this.res = res;
        this.fs = require('fs');
        this.params = this.req.params;
        this.passport = require('passport');
        this.authViews = { user : [], admin : [] };
        this.models = {};
        this.viewDir = '';

        // autoload currentModel
        this.model = this.getModel(this.params.model);

        this.viewVars = {url : req.url, user: req.user, helpers: {}};
        this.viewVars.flashMessages =  this.req.session.flashMessages || [];
        this.helpersDir = '../views/helpers/';
    }

    /**
     * send Mail using template
     *
     * @param view : String | email view
     * @param data : Object | may contain context vars and layout
     * @param callback
     */
    sendMailView(view, data, callback){

        // Set default layout if not
        data.layout = data.layout || 'emailLayout';

        // render template before send email
        this.req.app.render(view, data, function(err, hbsTemplate){

            let mailOptions = {
                from: data.from,
                to: data.target,
                subject: data.subject,
                text: data.message,
                html: hbsTemplate
            };

            // send mail with defined transport object
            mailTransporter.sendMail(mailOptions, callback);
        });

    }

    /**
     * Check if action is authorised
     * @param view
     * @param user
     */
    isAuthorized(view, user){

        let role = user ? user.role : null;

        Object.keys(this.authViews).forEach((key) => {
            if(~this.authViews[key].indexOf(view)){
                if(role !== key ){

                    this.viewVars.flashMessages.push({
                        type: 'danger',
                        message: 'Droits insuffisants pour accéder à la page demandée!'
                    });

                    this.failedAuth = true;
                }
            }

        });
    }

    /**
     * Do things before any actions
     * @returns {string|*}
     */
    beforeAction(){

        let action = this.req.params.action;
        let user = this.req.user;
        this.isAuthorized(action, user);

    }

    /**
     * Do things before render
     * @param view
     * @param data
     * @returns {string|*}
     */
    beforeRender(view, data){

        if(view){
            this.params.action = view;
        }

        if(data){
            this.viewVars = Object.assign(this.viewVars, data);
        }

        // LOG
        if(this.debug){
            console.log('[method] : ', this.req.method);
            console.log('[viewDir] : "' , this.viewDir,'", [action] "', this.params.action, '"');
            console.log('==================== [viewVars] ====================== ' );
            console.dir( this.viewVars, {showHidden : false, depth : 1, color : true});
        }

        this.view = path.join(this.viewDir , this.params.action);

        return this.view;
    }

    /**
     * get model based on model name in lowercase
     * @param modelName
     * @returns {*}
     */
    getModel(modelName){

        modelName = baseController.toModelName(modelName);
        let modelPath = path.join('..','models', modelName);
        if(!this.models[modelName]){
            try{
                let model = require(modelPath);
                model.controller = this;
                this.models[modelName] = model;
            }catch(e){
                return null;
            }
        }

        return this.models[modelName];
    }

    /**
     * Capitalize modelname
     * @param model
     * @returns {string}
     */
    static toModelName(model){
        return model.charAt(0).toUpperCase() + model.slice(1);
    }

    /**
     * Call self::beforeRender then render view
     * @param view : string | template of the view to render
     * @param data
     * @param render
     */
    render(view, data, render){

        this.beforeRender(view, data, render);

        switch(render){
            case 'json' :
                this.res.json(data);
                break;
            default :
                this.res.render(this.view , this.viewVars, (err, template) =>{
                    if(err){
                        this.res.statusCode = 500;
                        this.next(err);
                    }else{
                        this.res.send(template);
                    }
                });

                this.next();

                break;
        }
    }

    /**
     * Check if action exist
     * @param name
     * @returns {boolean}
     */
    actionExists(name){
        return name in this && typeof this[name] === 'function';
    }

    /**
     * Check if action exist and call it
     * @param name
     * @returns {boolean}
     */
    callAction(name){
        this.beforeAction();
        name = name + 'Action';
        if(this.actionExists(name)){
            // Auth requirement failed then redirect
            if(this.failedAuth){
                this.res.redirect('/');
                return true;
            }else{
                // TODO maybe return T/False from this.render in controller action
                // can be useful here
                this[name](this.params.arg);
                return true;
            }
        }else{
            return false;
        }
    }
}

module.exports = baseController;<|endoftext|>


<commit_before>/**
 * notify message_pusher event to clients via websocket and postMessage
 * @author codefirst
 */
(function($, document, undefined) {
    /**
     * notify message_pusher event to clients via websocket and postMessage
     * @param {Object} config.pusher message pusher object like Pusher, Keima, Socky
     * @return this
     */
    $.fn.webSocket = function(config){
        var target = this;

        var pusher = config.pusher;

        function fire(name, data){
            target.trigger("websocket::"+name, data);
            if(window.postMessage) {
                window.postMessage({ 'type': name,
                                     'current': AsakusaSatellite.current,
                                     'data': data
                                   }, location.origin);
            }
        }

        function parse(obj) {
            if(typeof(obj) == 'string') {
                return $.parseJSON(obj);
            } else {
                return obj;
            }
        }

        pusher.connection.bind('connected',
            function(e) { fire('connect', e); }
        );
        pusher.connection.bind('failed',
            function(e){ fire('error', e); }
        );
        pusher.connection.bind('disconnected',
            function(e){ fire('disconnect', e); }
        );

        var channel = pusher.subscribe('as-' + config.room );
        channel.bind('message_create',
            function(obj){ fire('create', parse(obj).content); }
        );
        channel.bind('message_update',
            function(obj){ fire('update', parse(obj).content); }
        );
        channel.bind('message_delete',
            function(obj){ fire('delete', parse(obj).content); }
        );

        return this;
    }
})(jQuery, document);
<commit_msg>bugfix: use location.protocol/host instead of location.origin refs #1412<commit_after>/**
 * notify message_pusher event to clients via websocket and postMessage
 * @author codefirst
 */
(function($, document, undefined) {
    /**
     * notify message_pusher event to clients via websocket and postMessage
     * @param {Object} config.pusher message pusher object like Pusher, Keima, Socky
     * @return this
     */
    $.fn.webSocket = function(config){
        var target = this;

        var pusher = config.pusher;

        function fire(name, data){
            target.trigger("websocket::"+name, data);
            if(window.postMessage) {
                window.postMessage({ 'type': name,
                                     'current': AsakusaSatellite.current,
                                     'data': data
                                   }, location.protocol+"//"+location.host);
            }
        }

        function parse(obj) {
            if(typeof(obj) == 'string') {
                return $.parseJSON(obj);
            } else {
                return obj;
            }
        }

        pusher.connection.bind('connected',
            function(e) { fire('connect', e); }
        );
        pusher.connection.bind('failed',
            function(e){ fire('error', e); }
        );
        pusher.connection.bind('disconnected',
            function(e){ fire('disconnect', e); }
        );

        var channel = pusher.subscribe('as-' + config.room );
        channel.bind('message_create',
            function(obj){ fire('create', parse(obj).content); }
        );
        channel.bind('message_update',
            function(obj){ fire('update', parse(obj).content); }
        );
        channel.bind('message_delete',
            function(obj){ fire('delete', parse(obj).content); }
        );

        return this;
    }
})(jQuery, document);
<|endoftext|>


<commit_before>var noReplicasetStart = process.env['NO_REPLICASET_START'] != null ? true : false;

var testCase = require('../../deps/nodeunit').testCase,
  debug = require('util').debug,
  inspect = require('util').inspect,
  gleak = require('../../tools/gleak'),
  ReplicaSetManager = require('../tools/replica_set_manager').ReplicaSetManager,
  Db = require('../../lib/mongodb').Db,
  ReplSetServers = require('../../lib/mongodb').ReplSetServers,
  Server = require('../../lib/mongodb').Server,
  Step = require("../../deps/step/lib/step");

// Keep instance of ReplicaSetManager
var serversUp = false;
var retries = 120;
var RS = RS == null ? null : RS;

var ensureConnection = function(test, numberOfTries, callback) {
  // Replica configuration
  var replSet = new ReplSetServers( [
      new Server( RS.host, RS.ports[1], { auto_reconnect: true } ),
      new Server( RS.host, RS.ports[0], { auto_reconnect: true } ),
      new Server( RS.host, RS.ports[2], { auto_reconnect: true } )
    ],
    {rs_name:RS.name}
  );

  if(numberOfTries <= 0) return callback(new Error("could not connect correctly"), null);

  var db = new Db('integration_test_', replSet);
  // Print any errors
  db.on("error", function(err) {
    console.log("============================= ensureConnection caught error")
    console.dir(err)
    if(err != null && err.stack != null) console.log(err.stack)
    db.close();
  })

  // Open the db
  db.open(function(err, p_db) {
    db.close();
    if(err != null) {
      // Wait for a sec and retry
      setTimeout(function() {
        numberOfTries = numberOfTries - 1;
        ensureConnection(test, numberOfTries, callback);
      }, 1000);
    } else {
      return callback(null, p_db);
    }
  })
}

module.exports = testCase({
  setUp: function(callback) {
    // Create instance of replicaset manager but only for the first call
    if(!serversUp && !noReplicasetStart) {
      serversUp = true;
      RS = new ReplicaSetManager({retries:120, secondary_count:2, passive_count:1, arbiter_count:1});
      RS.startSet(true, function(err, result) {
        if(err != null) throw err;
        // Finish setup
        callback();
      });
    } else {
      RS.restartKilledNodes(function(err, result) {
        if(err != null) throw err;
        callback();
      })
    }
  },

  tearDown: function(callback) {
    // RS.restartKilledNodes(function(err, result) {
    //   if(err != null) throw err;
      callback();
    // })
  },

  shouldReadPrimary : function(test) {
    // debug("=========================================== shouldReadPrimary")
    // Replica configuration
    var replSet = new ReplSetServers( [
        new Server( RS.host, RS.ports[0], { auto_reconnect: true } ),
      ],
      {rs_name:RS.name, read_secondary:true}
    );

    // Insert some data
    var db = new Db('integration_test_', replSet);
    db.open(function(err, p_db) {
      if(err != null) debug("shouldReadPrimary :: " + inspect(err));
      // Drop collection on replicaset
      p_db.dropCollection('testsets', function(err, r) {
        if(err != null) debug("shouldReadPrimary :: " + inspect(err));
        test.equal(false, p_db.serverConfig.isReadPrimary());
        test.equal(false, p_db.serverConfig.isPrimary());
        p_db.close();
        test.done();
      });
    })
  },

  shouldCorrectlyTestConnection : function(test) {
    // debug("=========================================== shouldCorrectlyTestConnection")
    // Replica configuration
    var replSet = new ReplSetServers( [
        new Server( RS.host, RS.ports[0], { auto_reconnect: true } ),
      ],
      {rs_name:RS.name, read_secondary:true}
    );

    // Insert some data
    var db = new Db('integration_test_', replSet);
    db.open(function(err, p_db) {
      if(err != null) debug("shouldReadPrimary :: " + inspect(err));

      // Drop collection on replicaset
      p_db.dropCollection('testsets', function(err, r) {
        if(err != null) debug("shouldReadPrimary :: " + inspect(err));

        test.ok(p_db.serverConfig.primary != null);
        test.ok(p_db.serverConfig.read != null);
        test.ok(p_db.serverConfig.primary.port != p_db.serverConfig.read.port);
        p_db.close();
        test.done();
      });
    })
  },

  shouldCorrectlyQuerySecondaries : function(test) {
    // debug("=========================================== shouldCorrectlyQuerySecondaries")
    var self = this;
    // Replica configuration
    var replSet = new ReplSetServers( [
        new Server( RS.host, RS.ports[0], { auto_reconnect: true } ),
        new Server( RS.host, RS.ports[1], { auto_reconnect: true } ),
        new Server( RS.host, RS.ports[2], { auto_reconnect: true } ),
      ],
      {rs_name:RS.name, read_secondary:true}
    );

    // Insert some data
    var db = new Db('integration_test_', replSet);
    db.open(function(err, p_db) {
      if(err != null) debug("shouldReadPrimary :: " + inspect(err));

      p_db.createCollection("testsets", {safe:{w:2, wtimeout:10000}}, function(err, collection) {
        if(err != null) debug("shouldReadPrimary :: " + inspect(err));

        collection.insert([{a:20}, {a:30}, {a:40}], {safe:{w:2, wtimeout:10000}}, function(err, result) {
          // Ensure replication happened in time
          setTimeout(function() {
            // Kill the primary
            RS.killPrimary(function(node) {
              // Do a collection find
              collection.find().toArray(function(err, items) {
                test.equal(null, err);
                test.equal(3, items.length);
                p_db.close();
                test.done();
              });
            });
          }, 2000);
        })
      });
    })
  },

  noGlobalsLeaked : function(test) {
    var leaks = gleak.detectNew();
    test.equal(0, leaks.length, "global var leak detected: " + leaks.join(', '));
    test.done();
  }
})

<commit_msg>Added a test to ensure that we are reading from primary when using a replicaset with read_secodary=true<commit_after>var noReplicasetStart = process.env['NO_REPLICASET_START'] != null ? true : false;

var testCase = require('../../deps/nodeunit').testCase,
  debug = require('util').debug,
  inspect = require('util').inspect,
  gleak = require('../../tools/gleak'),
  ReplicaSetManager = require('../tools/replica_set_manager').ReplicaSetManager,
  Db = require('../../lib/mongodb').Db,
  ReplSetServers = require('../../lib/mongodb').ReplSetServers,
  Server = require('../../lib/mongodb').Server,
  Step = require("../../deps/step/lib/step");

// Keep instance of ReplicaSetManager
var serversUp = false;
var retries = 120;
var RS = RS == null ? null : RS;

var ensureConnection = function(test, numberOfTries, callback) {
  // Replica configuration
  var replSet = new ReplSetServers( [
      new Server( RS.host, RS.ports[1], { auto_reconnect: true } ),
      new Server( RS.host, RS.ports[0], { auto_reconnect: true } ),
      new Server( RS.host, RS.ports[2], { auto_reconnect: true } )
    ],
    {rs_name:RS.name}
  );

  if(numberOfTries <= 0) return callback(new Error("could not connect correctly"), null);

  var db = new Db('integration_test_', replSet);
  // Print any errors
  db.on("error", function(err) {
    console.log("============================= ensureConnection caught error")
    console.dir(err)
    if(err != null && err.stack != null) console.log(err.stack)
    db.close();
  })

  // Open the db
  db.open(function(err, p_db) {
    db.close();
    if(err != null) {
      // Wait for a sec and retry
      setTimeout(function() {
        numberOfTries = numberOfTries - 1;
        ensureConnection(test, numberOfTries, callback);
      }, 1000);
    } else {
      return callback(null, p_db);
    }
  })
}

module.exports = testCase({
  setUp: function(callback) {
    // Create instance of replicaset manager but only for the first call
    if(!serversUp && !noReplicasetStart) {
      serversUp = true;
      RS = new ReplicaSetManager({retries:120, secondary_count:2, passive_count:1, arbiter_count:1});
      RS.startSet(true, function(err, result) {
        if(err != null) throw err;
        // Finish setup
        callback();
      });
    } else {
      RS.restartKilledNodes(function(err, result) {
        if(err != null) throw err;
        callback();
      })
    }
  },

  tearDown: function(callback) {
    // RS.restartKilledNodes(function(err, result) {
    //   if(err != null) throw err;
      callback();
    // })
  },

  shouldReadPrimary : function(test) {
    // debug("=========================================== shouldReadPrimary")
    // Replica configuration
    var replSet = new ReplSetServers( [
        new Server( RS.host, RS.ports[0], { auto_reconnect: true } ),
      ],
      {rs_name:RS.name, read_secondary:true}
    );

    // Insert some data
    var db = new Db('integration_test_', replSet);
    db.open(function(err, p_db) {
      if(err != null) debug("shouldReadPrimary :: " + inspect(err));
      // Drop collection on replicaset
      p_db.dropCollection('testsets', function(err, r) {
        if(err != null) debug("shouldReadPrimary :: " + inspect(err));
        test.equal(false, p_db.serverConfig.isReadPrimary());
        test.equal(false, p_db.serverConfig.isPrimary());
        p_db.close();
        test.done();
      });
    })
  },

  shouldCorrectlyTestConnection : function(test) {
    // debug("=========================================== shouldCorrectlyTestConnection")
    // Replica configuration
    var replSet = new ReplSetServers( [
        new Server( RS.host, RS.ports[0], { auto_reconnect: true } ),
      ],
      {rs_name:RS.name, read_secondary:true}
    );

    // Insert some data
    var db = new Db('integration_test_', replSet);
    db.open(function(err, p_db) {
      if(err != null) debug("shouldReadPrimary :: " + inspect(err));

      // Drop collection on replicaset
      p_db.dropCollection('testsets', function(err, r) {
        if(err != null) debug("shouldReadPrimary :: " + inspect(err));

        test.ok(p_db.serverConfig.primary != null);
        test.ok(p_db.serverConfig.read != null);
        test.ok(p_db.serverConfig.primary.port != p_db.serverConfig.read.port);
        p_db.close();
        test.done();
      });
    })
  },

  shouldCorrectlyQuerySecondaries : function(test) {
    // debug("=========================================== shouldCorrectlyQuerySecondaries")
    var self = this;
    // Replica configuration
    var replSet = new ReplSetServers( [
        new Server( RS.host, RS.ports[0], { auto_reconnect: true } ),
        new Server( RS.host, RS.ports[1], { auto_reconnect: true } ),
        new Server( RS.host, RS.ports[2], { auto_reconnect: true } ),
      ],
      {rs_name:RS.name, read_secondary:true}
    );

    // Insert some data
    var db = new Db('integration_test_', replSet);
    db.open(function(err, p_db) {
      if(err != null) debug("shouldReadPrimary :: " + inspect(err));

      p_db.createCollection("testsets", {safe:{w:2, wtimeout:10000}}, function(err, collection) {
        if(err != null) debug("shouldReadPrimary :: " + inspect(err));

        collection.insert([{a:20}, {a:30}, {a:40}], {safe:{w:2, wtimeout:10000}}, function(err, result) {
          // Ensure replication happened in time
          setTimeout(function() {
            // Kill the primary
            RS.killPrimary(function(node) {
              // Do a collection find
              collection.find().toArray(function(err, items) {
                test.equal(null, err);
                test.equal(3, items.length);
                p_db.close();
                test.done();
              });
            });
          }, 2000);
        })
      });
    })
  },

  shouldCorrectlyQuerySecondaries : function(test) {
    // debug("=========================================== shouldCorrectlyQuerySecondaries")
    var self = this;
    // Replica configuration
    var replSet = new ReplSetServers( [
        new Server( RS.host, RS.ports[0], { auto_reconnect: true } ),
        new Server( RS.host, RS.ports[1], { auto_reconnect: true } ),
        new Server( RS.host, RS.ports[2], { auto_reconnect: true } ),
      ],
      {rs_name:RS.name, read_secondary:false}
    );

    // Insert some data
    var db = new Db('integration_test_', replSet);
    db.open(function(err, p_db) {
      if(err != null) debug("shouldReadPrimary :: " + inspect(err));

      // Ensure the checkoutReader gives us the actual writer object
      var reader = replSet.checkoutReader();
      var writer = replSet.checkoutWriter();
      // Ensure the connections are the same
      test.equal(reader.socketOptions.host, writer.socketOptions.host);
      test.equal(reader.socketOptions.port, writer.socketOptions.port);
      // Close connection to Spain
      db.close();
      test.done();
    })
  },

  noGlobalsLeaked : function(test) {
    var leaks = gleak.detectNew();
    test.equal(0, leaks.length, "global var leak detected: " + leaks.join(', '));
    test.done();
  }
})

<|endoftext|>


<commit_before>/*
 *  base64.js
 *
 *  Licensed under the BSD 3-Clause License.
 *    http://opensource.org/licenses/BSD-3-Clause
 *
 *  References:
 *    http://en.wikipedia.org/wiki/Base64
 */
;(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined'
        ? module.exports = factory(global)
        : typeof define === 'function' && define.amd
        ? define(factory) : factory(global)
}((
    typeof self !== 'undefined' ? self
        : typeof window !== 'undefined' ? window
        : typeof global !== 'undefined' ? global
: this
), function(global) {
    'use strict';
    // existing version for noConflict()
    global = global || {};
    var _Base64 = global.Base64;
    var version = "2.6.1";
    // constants
    var b64chars
        = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    var b64tab = function(bin) {
        var t = {};
        for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i;
        return t;
    }(b64chars);
    var fromCharCode = String.fromCharCode;
    // encoder stuff
    var cb_utob = function(c) {
        if (c.length < 2) {
            var cc = c.charCodeAt(0);
            return cc < 0x80 ? c
                : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6))
                                + fromCharCode(0x80 | (cc & 0x3f)))
                : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f))
                    + fromCharCode(0x80 | ((cc >>>  6) & 0x3f))
                    + fromCharCode(0x80 | ( cc         & 0x3f)));
        } else {
            var cc = 0x10000
                + (c.charCodeAt(0) - 0xD800) * 0x400
                + (c.charCodeAt(1) - 0xDC00);
            return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07))
                    + fromCharCode(0x80 | ((cc >>> 12) & 0x3f))
                    + fromCharCode(0x80 | ((cc >>>  6) & 0x3f))
                    + fromCharCode(0x80 | ( cc         & 0x3f)));
        }
    };
    var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
    var utob = function(u) {
        return u.replace(re_utob, cb_utob);
    };
    var cb_encode = function(ccc) {
        var padlen = [0, 2, 1][ccc.length % 3],
        ord = ccc.charCodeAt(0) << 16
            | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8)
            | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)),
        chars = [
            b64chars.charAt( ord >>> 18),
            b64chars.charAt((ord >>> 12) & 63),
            padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63),
            padlen >= 1 ? '=' : b64chars.charAt(ord & 63)
        ];
        return chars.join('');
    };
    var btoa = global.btoa && typeof global.btoa == 'function'
        ? function(b){ return global.btoa(b) } : function(b) {
        if (b.match(/[^\x00-\xFF]/)) throw new RangeError(
            'The string contains invalid characters.'
        );
        return b.replace(/[\s\S]{1,3}/g, cb_encode);
    };
    var _encode = function(u) {
        return btoa(utob(String(u)));
    };
    var encode = function(u, urisafe) {
        return !urisafe
            ? _encode(String(u))
            : _encode(String(u)).replace(/[+\/]/g, function(m0) {
                return m0 == '+' ? '-' : '_';
            }).replace(/=/g, '');
    };
    var encodeURI = function(u) { return encode(u, true) };
    var fromUint8Array = function(a) {
        return btoa(Array.from(a, function(c) {
            return String.fromCharCode(c)
        }).join(''));
    };
    // decoder stuff
    var re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g;
    var cb_btou = function(cccc) {
        switch(cccc.length) {
        case 4:
            var cp = ((0x07 & cccc.charCodeAt(0)) << 18)
                |    ((0x3f & cccc.charCodeAt(1)) << 12)
                |    ((0x3f & cccc.charCodeAt(2)) <<  6)
                |     (0x3f & cccc.charCodeAt(3)),
            offset = cp - 0x10000;
            return (fromCharCode((offset  >>> 10) + 0xD800)
                    + fromCharCode((offset & 0x3FF) + 0xDC00));
        case 3:
            return fromCharCode(
                ((0x0f & cccc.charCodeAt(0)) << 12)
                    | ((0x3f & cccc.charCodeAt(1)) << 6)
                    |  (0x3f & cccc.charCodeAt(2))
            );
        default:
            return  fromCharCode(
                ((0x1f & cccc.charCodeAt(0)) << 6)
                    |  (0x3f & cccc.charCodeAt(1))
            );
        }
    };
    var btou = function(b) {
        return b.replace(re_btou, cb_btou);
    };
    var cb_decode = function(cccc) {
        var len = cccc.length,
        padlen = len % 4,
        n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0)
            | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0)
            | (len > 2 ? b64tab[cccc.charAt(2)] <<  6 : 0)
            | (len > 3 ? b64tab[cccc.charAt(3)]       : 0),
        chars = [
            fromCharCode( n >>> 16),
            fromCharCode((n >>>  8) & 0xff),
            fromCharCode( n         & 0xff)
        ];
        chars.length -= [0, 0, 2, 1][padlen];
        return chars.join('');
    };
    var _atob = global.atob && typeof global.atob == 'function'
        ? function(a){ return global.atob(a) } : function(a){
        return a.replace(/\S{1,4}/g, cb_decode);
    };
    var atob = function(a) {
        return _atob(String(a).replace(/[^A-Za-z0-9\+\/]/g, ''));
    };
    var _decode = function(a) { return btou(_atob(a)) };
    var decode = function(a){
        return _decode(
            String(a).replace(/[-_]/g, function(m0) {
                return m0 == '-' ? '+' : '/'
            }).replace(/[^A-Za-z0-9\+\/]/g, '')
        );
    };
    var toUint8Array = function(a) {
        return Uint8Array.from(atob(a), function(c) {
            return c.charCodeAt(0);
        });
    };
    var noConflict = function() {
        var Base64 = global.Base64;
        global.Base64 = _Base64;
        return Base64;
    };
    // export Base64
    global.Base64 = {
        VERSION: version,
        atob: atob,
        btoa: btoa,
        fromBase64: decode,
        toBase64: encode,
        utob: utob,
        encode: encode,
        encodeURI: encodeURI,
        btou: btou,
        decode: decode,
        noConflict: noConflict,
        fromUint8Array: fromUint8Array,
        toUint8Array: toUint8Array
    };
    // if ES5 is available, make Base64.extendString() available
    if (typeof Object.defineProperty === 'function') {
        var noEnum = function(v){
            return {value:v,enumerable:false,writable:true,configurable:true};
        };
        global.Base64.extendString = function () {
            Object.defineProperty(
                String.prototype, 'fromBase64', noEnum(function () {
                    return decode(this)
                }));
            Object.defineProperty(
                String.prototype, 'toBase64', noEnum(function (urisafe) {
                    return encode(this, urisafe)
                }));
            Object.defineProperty(
                String.prototype, 'toBase64URI', noEnum(function () {
                    return encode(this, true)
                }));
        };
    }
    //
    // export Base64 to the namespace
    //
    if (global['Meteor']) { // Meteor.js
        Base64 = global.Base64;
    }
    // module.exports and AMD are mutually exclusive.
    // module.exports has precedence.
    if (typeof module !== 'undefined' && module.exports) {
        module.exports.Base64 = global.Base64;
    }
    else if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define([], function(){ return global.Base64 });
    }
    // that's it!
    return {Base64: global.Base64}
}));
<commit_msg>improve .{from,to}Uint8Array<commit_after>/*
 *  base64.js
 *
 *  Licensed under the BSD 3-Clause License.
 *    http://opensource.org/licenses/BSD-3-Clause
 *
 *  References:
 *    http://en.wikipedia.org/wiki/Base64
 */
;(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined'
        ? module.exports = factory(global)
        : typeof define === 'function' && define.amd
        ? define(factory) : factory(global)
}((
    typeof self !== 'undefined' ? self
        : typeof window !== 'undefined' ? window
        : typeof global !== 'undefined' ? global
: this
), function(global) {
    'use strict';
    // existing version for noConflict()
    global = global || {};
    var _Base64 = global.Base64;
    var version = "2.6.1";
    // constants
    var b64chars
        = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    var b64tab = function(bin) {
        var t = {};
        for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i;
        return t;
    }(b64chars);
    var fromCharCode = String.fromCharCode;
    // encoder stuff
    var cb_utob = function(c) {
        if (c.length < 2) {
            var cc = c.charCodeAt(0);
            return cc < 0x80 ? c
                : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6))
                                + fromCharCode(0x80 | (cc & 0x3f)))
                : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f))
                    + fromCharCode(0x80 | ((cc >>>  6) & 0x3f))
                    + fromCharCode(0x80 | ( cc         & 0x3f)));
        } else {
            var cc = 0x10000
                + (c.charCodeAt(0) - 0xD800) * 0x400
                + (c.charCodeAt(1) - 0xDC00);
            return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07))
                    + fromCharCode(0x80 | ((cc >>> 12) & 0x3f))
                    + fromCharCode(0x80 | ((cc >>>  6) & 0x3f))
                    + fromCharCode(0x80 | ( cc         & 0x3f)));
        }
    };
    var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
    var utob = function(u) {
        return u.replace(re_utob, cb_utob);
    };
    var cb_encode = function(ccc) {
        var padlen = [0, 2, 1][ccc.length % 3],
        ord = ccc.charCodeAt(0) << 16
            | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8)
            | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)),
        chars = [
            b64chars.charAt( ord >>> 18),
            b64chars.charAt((ord >>> 12) & 63),
            padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63),
            padlen >= 1 ? '=' : b64chars.charAt(ord & 63)
        ];
        return chars.join('');
    };
    var btoa = global.btoa && typeof global.btoa == 'function'
        ? function(b){ return global.btoa(b) } : function(b) {
        if (b.match(/[^\x00-\xFF]/)) throw new RangeError(
            'The string contains invalid characters.'
        );
        return b.replace(/[\s\S]{1,3}/g, cb_encode);
    };
    var _encode = function(u) {
        return btoa(utob(String(u)));
    };
    var mkUriSafe = function (b64) {
        return b64.replace(/[+\/]/g, function(m0) {
            return m0 == '+' ? '-' : '_';
        }).replace(/=/g, '');
    };
    var encode = function(u, urisafe) {
        return urisafe ? mkUriSafe(_encode(u)) : _encode(u);
    };
    var encodeURI = function(u) { return encode(u, true) };
    var fromUint8Array;
    if (global.Uint8Array) fromUint8Array = function(a, urisafe) {
        // return btoa(fromCharCode.apply(null, a));
        var b64 = '';
        for (var i = 0, l = a.length; i < l; i += 3) {
            var a0 = a[i], a1 = a[i+1], a2 = a[i+2];
            var ord = a0 << 16 | a1 << 8 | a2;
            b64 +=    b64chars.charAt( ord >>> 18)
                +     b64chars.charAt((ord >>> 12) & 63)
                + ( typeof a1 != 'undefined'
                    ? b64chars.charAt((ord >>>  6) & 63) : '=')
                + ( typeof a2 != 'undefined'
                    ? b64chars.charAt( ord         & 63) : '=');
        }
        return urisafe ? mkUriSafe(b64) : b64;
    };
    // decoder stuff
    var re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g;
    var cb_btou = function(cccc) {
        switch(cccc.length) {
        case 4:
            var cp = ((0x07 & cccc.charCodeAt(0)) << 18)
                |    ((0x3f & cccc.charCodeAt(1)) << 12)
                |    ((0x3f & cccc.charCodeAt(2)) <<  6)
                |     (0x3f & cccc.charCodeAt(3)),
            offset = cp - 0x10000;
            return (fromCharCode((offset  >>> 10) + 0xD800)
                    + fromCharCode((offset & 0x3FF) + 0xDC00));
        case 3:
            return fromCharCode(
                ((0x0f & cccc.charCodeAt(0)) << 12)
                    | ((0x3f & cccc.charCodeAt(1)) << 6)
                    |  (0x3f & cccc.charCodeAt(2))
            );
        default:
            return  fromCharCode(
                ((0x1f & cccc.charCodeAt(0)) << 6)
                    |  (0x3f & cccc.charCodeAt(1))
            );
        }
    };
    var btou = function(b) {
        return b.replace(re_btou, cb_btou);
    };
    var cb_decode = function(cccc) {
        var len = cccc.length,
        padlen = len % 4,
        n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0)
            | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0)
            | (len > 2 ? b64tab[cccc.charAt(2)] <<  6 : 0)
            | (len > 3 ? b64tab[cccc.charAt(3)]       : 0),
        chars = [
            fromCharCode( n >>> 16),
            fromCharCode((n >>>  8) & 0xff),
            fromCharCode( n         & 0xff)
        ];
        chars.length -= [0, 0, 2, 1][padlen];
        return chars.join('');
    };
    var _atob = global.atob && typeof global.atob == 'function'
        ? function(a){ return global.atob(a) } : function(a){
        return a.replace(/\S{1,4}/g, cb_decode);
    };
    var atob = function(a) {
        return _atob(String(a).replace(/[^A-Za-z0-9\+\/]/g, ''));
    };
    var _decode = function(a) { return btou(_atob(a)) };
    var decode = function(a){
        return _decode(
            String(a).replace(/[-_]/g, function(m0) {
                return m0 == '-' ? '+' : '/'
            }).replace(/[^A-Za-z0-9\+\/]/g, '')
        );
    };
    var toUint8Array;
    if (global.Uint8Array) toUint8Array = function(a) {
        return Uint8Array.from(atob(a), function(c) {
            return c.charCodeAt(0);
        });
    };
    var noConflict = function() {
        var Base64 = global.Base64;
        global.Base64 = _Base64;
        return Base64;
    };
    // export Base64
    global.Base64 = {
        VERSION: version,
        atob: atob,
        btoa: btoa,
        fromBase64: decode,
        toBase64: encode,
        utob: utob,
        encode: encode,
        encodeURI: encodeURI,
        btou: btou,
        decode: decode,
        noConflict: noConflict,
        fromUint8Array: fromUint8Array,
        toUint8Array: toUint8Array
    };
    // if ES5 is available, make Base64.extendString() available
    if (typeof Object.defineProperty === 'function') {
        var noEnum = function(v){
            return {value:v,enumerable:false,writable:true,configurable:true};
        };
        global.Base64.extendString = function () {
            Object.defineProperty(
                String.prototype, 'fromBase64', noEnum(function () {
                    return decode(this)
                }));
            Object.defineProperty(
                String.prototype, 'toBase64', noEnum(function (urisafe) {
                    return encode(this, urisafe)
                }));
            Object.defineProperty(
                String.prototype, 'toBase64URI', noEnum(function () {
                    return encode(this, true)
                }));
        };
    }
    //
    // export Base64 to the namespace
    //
    if (global['Meteor']) { // Meteor.js
        Base64 = global.Base64;
    }
    // module.exports and AMD are mutually exclusive.
    // module.exports has precedence.
    if (typeof module !== 'undefined' && module.exports) {
        module.exports.Base64 = global.Base64;
    }
    else if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define([], function(){ return global.Base64 });
    }
    // that's it!
    return {Base64: global.Base64}
}));
<|endoftext|>