<commit_before>/**
 * qUnitScraper object
 */
var qUnitScraper = {
    /**
     * Start here!
     * This is the first method to invoke to call other method.
     * Currently it can only does the call to other methods and doesn't do any processing here.
     * It then should return all the failed modules in object format back to caller.
     *
     * @params : none
     * @return : (object) the object listing all the failed modules along with their information
     */
    init: function() {
        // validate page here

        var results = this._readResults();
        return( results );
    },
    /**
     * _readResults create a jQuery object, selecting output listing.
     * Currently it's looking only for the failed modules, but could be
     * extended to specify which to look for.
     * It calls other methods to get the information it needs and returns an object
     * listing each method indexed by the method number as displayed to user.
     *
     * @params : none
     * @return : (object) listing all the failed modules along with their information.
     */
    _readResults: function( ) {
        var modules = jQuery("#qunit-tests .fail[id^=qunit-test-output]");
        var moduleResults = {};

        var numModules = modules.length;
        for( var moduleNumber=0; moduleNumber < numModules; moduleNumber++ )
        {
            var thisModule = modules[moduleNumber];
            moduleResults["module " + this._getModuleNumber(jQuery(thisModule))] = this._readModule( thisModule );
        }

        return moduleResults;
    },
    /**
     * This method takes jQuery object of the modules we want to read.
     * It then searches for the assert list result, currently the failed ones.
     * Like _readResults, it could be extended.
     * The method puts together the list found, builds an object including the name, message and source
     * and returns it.
     *
     * @params : (object) jQuery object of the module we want to read
     * @return : (object) an object with 2 properties, name of test and another object listing the tests
     */
    _readModule: function( module ) {
        var tests   = jQuery(".qunit-assert-list .fail", module);
        var testResults = {
            "name" : jQuery(".module-name", module).html() + ": " + jQuery(".test-name", module).html(),
            "tests": []
        };

        var numTests = tests.length;
        for( var testNumber=0; testNumber < numTests; testNumber++ ) {
            var thisTest = tests[testNumber];
            testResults["tests"].push({
                "message": jQuery(".test-message", thisTest).html(),
                "source" : jQuery(".test-source pre", thisTest).html()
            });
        }

        return testResults;
    },
    /**
     * This one takes a jQuery object of the module we want to find the number.
     * Performs a regex match over the id of the DOM which includes an index at the very end.
     * Lastly, we add 1 to the number since the ID is 0-indexed vs the list display to user is 1-indexed.
     *
     * @params : (object) jQuery object of the module element
     * @return : (int) module number as display to users
     */
    _getModuleNumber: function( module ) {
        var id = module.attr( "id" );
        var match = id.match( /\d+$/ )[0];
        return parseInt( match ) + 1 ;
    }
}<commit_msg>Expand functionality to read both passed and failed tests<commit_after>/**
 * qUnitScraper object
 */
var qUnitScraper = {
    /**
     * Start here!
     * This is the first method to invoke to call other method.
     * Currently it can only does the call to other methods and doesn't do any processing here.
     * It then should return all the failed modules in object format back to caller.
     *
     * @params : none
     * @return : (object) the object listing all the failed modules along with their information
     */
    init: function() {
        // validate page here

        var results = {
            "pass" : this._readResults(".pass"),
            "fail" : this._readResults(".fail")
        };
        return( results );
    },
    /**
     * _readResults first creates a jQuery object, selecting output listing.
     * It then calls _readModule method to get the information it needs about each module and returns an object
     * listing each method indexed by the method number as displayed to user.
     *
     * @params : (string) selector class name with the dot prefix, it should be either ".pass" or ".fail"
     * @return : (object) listing all the failed modules along with their information.
     */
    _readResults: function( type ) {
        var modules = jQuery("[id^=qunit-test-output]");
        var moduleResults = {};

        var numModules = modules.length;
        for( var moduleNumber=0; moduleNumber < numModules; moduleNumber++ ) {
            var thisModule = modules[moduleNumber];
            if( jQuery(type, thisModule).length == 0 ) {
                continue;
            }
            else {
                moduleResults["module " + this._getModuleNumber(jQuery(thisModule))] = this._readModule( thisModule, type );
            }
        }

        return moduleResults;
    },
    /**
     * This method takes jQuery object of the modules we want to read.
     * It then searches for the assert list result based on the class type parameter passed (.pass or .fail).
     * The method puts together the list found, builds an object including the name, message and source
     * and returns it.
     *
     * @params : module (object) jQuery object of the module we want to read
     *           type   (string) selector class name with the dot prefix, it should be either ".pass" or ".fail"
     * @return : (object) an object with 2 properties, name of test and another object listing the tests
     */
    _readModule: function( module, type ) {
        var tests   = jQuery(".qunit-assert-list " + type, module);
        var testResults = {
            "name" : jQuery(".module-name", module).html() + ": " + jQuery(".test-name", module).html(),
            "tests": []
        };

        var numTests = tests.length;
        for( var testNumber=0; testNumber < numTests; testNumber++ ) {
            var thisTest = tests[testNumber];
            testResults["tests"].push({
                "message": jQuery(".test-message", thisTest).html(),
                "source" : jQuery(".test-source pre", thisTest).html()
            });
        }

        return testResults;
    },
    /**
     * This one takes a jQuery object of the module we want to find the number.
     * Performs a regex match over the id of the DOM which includes an index at the very end.
     * Lastly, we add 1 to the number since the ID is 0-indexed vs the list display to user is 1-indexed.
     *
     * @params : (object) jQuery object of the module element
     * @return : (int) module number as display to users
     */
    _getModuleNumber: function( module ) {
        var id = module.attr( "id" );
        var match = id.match( /\d+$/ )[0];
        return parseInt( match ) + 1 ;
    }
}<|endoftext|>


<commit_before>import Promise from 'bluebird';
import request from 'superagent-bluebird-promise';

const apmApi = process.env.ATOM_API_URL || 'https://atom.io/api';

export default function fetch(port, config, path, modules) {
    let nodeModules = Promise.all(modules.map(module => (
        request.get(`${apmApi}/packages/${module}`).promise()
    ))).reduce(dependencies, extension => {
        extension = JSON.parse(extension.text);
        let pkg = extension.versions[extension.releases.latest];
        let deps = pkg.dependencies;
        return [...dependencies, ...Object.keys(deps).map(dep => (`${dep}@${deps[dep]}`))];
    }, []);
}
<commit_msg>now returns an object of the tgz dist<commit_after>import Promise from 'bluebird';
import request from 'superagent-bluebird-promise';

const apmApi = process.env.ATOM_API_URL || 'https://atom.io/api';

export default function fetch(port, config, path, modules) {
    let { dependencies, extensions } = Promise.all(modules.map(module => (
        request.get(`${apmApi}/packages/${module}`).promise()
    ))).reduce(({ dependencies, extensions }, extension) => {
        extension = JSON.parse(extension.text);
        let pkg = extension.versions[extension.releases.latest];
        let deps = pkg.dependencies;
        return {
            dependencies: [...dependencies, ...Object.keys(deps).map(dep => (`${dep}@${deps[dep]}`))],
            extensions: {
                [`${pkg.name}@${pkg.version}`]: pkg.dist.tarball
            }
        }
    }, {
        dependencies: [],
        extensions: {}
    }).then(({ dependencies, extensions }) => {
    });
}
<|endoftext|>


<commit_before>const AWS = require('aws-sdk');

require('./kubernetes');
const {capitalize, capitalizeFieldNames, delay, isTransientNetworkError} = require('./utils');

const logger = require('log4js').getLogger('S3');

/**
 * A bucket resource in Kubernetes
 *
 * @typedef Bucket
 * @property {KubernetesMetadata} metadata
 * @property {BucketSpec} spec
 * @property {BucketStatus} [status]
 */

/**
 * A bucket specification
 *
 * @typedef BucketSpec
 * @property {("private"|"public-read"|"public-read-write"|"aws-exec-read"|"authenticated-read"|"bucket-owner-read"|"bucket-owner-full-control"|"log-delivery-write")} [acl] The canned ACL to apply to the bucket
 * @property {CreateBucketConfiguration} [createBucketConfiguration]
 * @property {LoggingConfiguration} [loggingConfiguration]
 * @property {BucketEncryption} [bucketEncryption] optional configuration for SSE
 */

/**
 * @typedef CreateBucketConfiguration
 * @property {("EU"|"eu-west-1"|"us-west-1"|"us-west-2"|"ap-south-1"|"ap-southeast-1"|"ap-southeast-2"|"ap-northeast-1"|"sa-east-1"|"cn-north-1"|"eu-central-1")} locationConstraint
 */

/**
 * Configuration of S3 bucket access logging.
 *
 * This structure is based on the definition in CloudFormation.
 *
 * @typedef LoggingConfiguration
 * @property {string} destinationBucketName
 * @property {string} logFilePrefix
 */

/**
 * A adapter for modifying AWS S3 buckets using Bucket definitions
 */
class S3Bucket { // eslint-disable-line padded-blocks
	/**
	 *
	 * @param {Object} [options] S3 client options
	 */
	constructor(options = {}) {
		this.s3 = new AWS.S3(options);
	}

	/**
	 * Translate the logging configuration into the 'logging params' for the AWS SDK.
	 *
	 * @param {string} bucketName the bucket name
	 * @param {LoggingConfiguration} loggingConfiguration logging configuration
	 * @returns {Object} the parameters for `putBucketLogging`
	 */
	_translateLoggingConfiguration(bucketName, loggingConfiguration) {
		let status;
		if (!loggingConfiguration) {
			status = {};
		} else {
			status = {
				LoggingEnabled: {
					TargetBucket: loggingConfiguration.destinationBucketName,
					TargetPrefix: loggingConfiguration.logFilePrefix,
				}
			};
		}

		return {
			Bucket: bucketName,
			BucketLoggingStatus: status
		};
	}

	/**
	 * Translate the logging configuration into the 'logging params' for the AWS SDK.
	 *
	 * @param {string} bucketName the bucket name
	 * @param {PublicAccessBlockConfiguration} publicAccessBlockConfiguration Public Access Block configuration
	 * @returns {Object} the parameters for `putPublicAccessBlock`
	 */
	_translatePublicAccessBlockConfiguration(bucketName, publicAccessBlockConfiguration) {
		let status;
		if (!publicAccessBlockConfiguration) {
			status = {};
		} else {
			status = {
				BlockPublicAcls: publicAccessBlockConfiguration.blockPublicAcls,
			};
		}

		return {
			Bucket: bucketName,
			PublicAccessBlockConfiguration: status
		};
	}

	/**
	 * Translate the SSE configuration into the 'server-side encryption params' for the AWS SDK.
	 *
	 * @param {string} bucketName the bucket name
	 * @param {BucketEncryption} bucketEncryption Bucket encryption (as per https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-bucketencryption.html)
	 * @returns {Object} the parameters for `putBucketEncryption`, or `null`
	 */
	_translateBucketEncryption(bucketName, bucketEncryption) {
		if (!bucketEncryption || !bucketEncryption.serverSideEncryptionConfiguration) {
			return null;
		}

		const rules = bucketEncryption.serverSideEncryptionConfiguration.map(rule => {
			// Determine the type of rule by looking at the keys in the rule
			// We need to do a case-insensitive comparison here!
			if (rule.serverSideEncryptionByDefault) {
				switch (rule.serverSideEncryptionByDefault.sseAlgorithm) {
				case 'AES256':
					// Sanity check: This will otherwise produce errors when applying the configuration
					if (rule.serverSideEncryptionByDefault.kmsMasterKeyId) {
						throw new Error('Unexpected kmsMasterKeyId in AES256 SSE configuration');
					}
					return {
						ApplyServerSideEncryptionByDefault: {
							SSEAlgorithm: rule.serverSideEncryptionByDefault.sseAlgorithm,
						},
					};
				case 'aws:kms':
					return {
						ApplyServerSideEncryptionByDefault: {
							KMSMasterKeyId: rule.serverSideEncryptionByDefault.kmsMasterKeyId,
							SSEAlgorithm: rule.serverSideEncryptionByDefault.sseAlgorithm,
						},
					};

				default:
					throw new Error(`Unsupported SSE algorithm ${rule.serverSideEncryptionByDefault.sseAlgorithm} for default encryption`);
				}
			}

			throw new Error(`Unsupport SSE rule with keys: ${Object.keys(rule)}`);
		});
		if (rules.length === 0) {
			// No rules: Assume no intent to configure default bucket encryption
			// This is different from "invalid rule"!
			return null;
		}

		return {
			Bucket: bucketName,
			ServerSideEncryptionConfiguration: {
				Rules: rules,
			},
		};
	}

	/**
	 * Convert the bucket.spec into parameters for the various AWS SDK operations.
	 *
	 * The resulting elements do not have the bucket name set.
	 *
	 * @param {Bucket} bucket a bucket definition
	 * @return {Object} the bucket attributes
	 */
	_translateSpec(bucket) {
		// Split the spec into parts
		const {loggingConfiguration, bucketEncryption, publicAccessBlockConfiguration, ...otherAttributes} = bucket.spec;
		const attributes = Object.keys(otherAttributes || {}).reduce((result, key) => {
			const value = bucket.spec[key];
			let resultKey;
			switch (key) {
			case 'acl':
				resultKey = key.toUpperCase();
				break;
			default:
				resultKey = capitalize(key);
				break;
			}
			// Convert to string
			const resultValue = capitalizeFieldNames(value);
			logger.debug(`[${bucket.metadata.name}]: Attribute ${key} = ${JSON.stringify(resultValue)}`);

			result[resultKey] = resultValue;
			return result;
		}, {});
		return {
			attributes,
			loggingParams: this._translateLoggingConfiguration(bucket.metadata.name, loggingConfiguration),
			publicAccessBlockParams: this._translatePublicAccessBlockConfiguration(bucket.metadata.name, publicAccessBlockConfiguration),
			sseParams: this._translateBucketEncryption(bucket.metadata.name, bucketEncryption),
		};
	}

	// XXX: logName could be awsOperation.name, except that that is empty for AWS?
	async _retryOnTransientNetworkErrors(logName, awsOperation, awsArguments) {
		const errorRetryDelay = 30000;
		try {
			return await awsOperation.apply(this.s3, awsArguments).promise();
		} catch (err) {
			if (isTransientNetworkError(err)) {
				logger.warn(`[${logName}]: transient ${err.code} ${err.errno}, retrying in ${errorRetryDelay / 1000}s`);
				await delay(errorRetryDelay);
				return this._retryOnTransientNetworkErrors(logName, awsOperation, awsArguments);
			}

			logger.warn(`[${logName}]: non-retryable error in operation: ${err.message}`);
			throw err;
		}
	}

	_reportError(logName, err, description) {
		logger.warn(`[${logName}]: ${description}: ${err.message}`);
		throw err;
	}

	async _createBucket(bucketName, attributes) {
		if (attributes.Bucket && attributes.Bucket !== bucketName) {
			throw new Error(`Inconsistent bucket name in configuration: ${bucketName} !== ${attributes.Bucket}`);
		}
		const request = Object.assign({}, attributes, {
			Bucket: bucketName
		});
		try {
			return await this._retryOnTransientNetworkErrors('S3::CreateBucket', this.s3.createBucket, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot create bucket');
		}
	}

	async _putBucketLogging(bucketName, loggingAttributes) {
		if (loggingAttributes.Bucket && loggingAttributes.Bucket !== bucketName) {
			throw new Error(`Inconsistent bucket name in configuration: ${bucketName} !== ${loggingAttributes.Bucket}`);
		}
		const request = Object.assign({}, loggingAttributes, {
			Bucket: bucketName
		});
		try {
			return await this._retryOnTransientNetworkErrors('S3::PutBucketLogging', this.s3.putBucketLogging, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot configure bucket logging');
		}
	}

	async _putBucketEncryption(bucketName, sseAttributes) {
		if (sseAttributes.Bucket && sseAttributes.Bucket !== bucketName) {
			throw new Error(`Inconsistent bucket name in configuration: ${bucketName} !== ${sseAttributes.Bucket}`);
		}
		const request = Object.assign({}, sseAttributes, {
			Bucket: bucketName
		});
		try {
			return await this._retryOnTransientNetworkErrors('S3::PutBucketEncryption', this.s3.putBucketEncryption, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot configure bucket encryption');
		}
	}

	async _putPublicAccessBlock(bucketName, publicAccessBlockParams) {
		if (publicAccessBlockParams.Bucket && publicAccessBlockParams.Bucket !== bucketName) {
			throw new Error(`Inconsistent bucket name in configuration: ${bucketName} !== ${publicAccessBlockParams.Bucket}`);
		}
		const request = Object.assign({}, publicAccessBlockParams, {
			Bucket: bucketName,
		});
		try {
			return await this._retryOnTransientNetworkErrors('S3::PutPublicAccessBlock', this.s3.putPublicAccessBlock, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot configure Block Public Access for bucket');
		}
	}

	async _putBucketAcl(bucketName, aclAttributes) {
		if (aclAttributes.Bucket && aclAttributes.Bucket !== bucketName) {
			throw new Error(`Inconsistent bucket name in configuration: ${bucketName} !== ${aclAttributes.Bucket}`);
		}
		const request = Object.assign({}, aclAttributes, {
			Bucket: bucketName
		});
		try {
			return await this._retryOnTransientNetworkErrors('S3::PutBucketAcl', this.s3.putBucketAcl, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot configure bucket ACL');
		}
	}

	async _deleteBucket(bucketName) {
		const request = {
			Bucket: bucketName
		};
		try {
			return await this._retryOnTransientNetworkErrors('S3::DeleteBucket', this.s3.deleteBucket, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot delete bucket');
		}
	}

	async _deleteBucketEncryption(bucketName) {
		const request = {
			Bucket: bucketName
		};
		try {
			return await this._retryOnTransientNetworkErrors('S3::DeleteBucketEncryption', this.s3.deleteBucketEncryption, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot remove bucket encryption');
		}
	}

	async _headBucket(bucketName) {
		const request = {
			Bucket: bucketName
		};
		try {
			return await this._retryOnTransientNetworkErrors('S3::HeadBucket', this.s3.headBucket, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot head bucket');
		}
	}

	async _getBucketLocation(bucketName) {
		const request = {
			Bucket: bucketName
		};
		try {
			return await this._retryOnTransientNetworkErrors('S3::GetBucketLocation', this.s3.getBucketLocation, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot get bucket location');
		}
	}

	/**
	 * Create a new bucket
	 *
	 * @param {Bucket} bucket Bucket definition in Kubernetes
	 * @return {Promise<any>} promise that resolves when the bucket is created
	 */
	async create(bucket) {
		const {attributes, loggingParams, publicAccessBlockParams, sseParams} = this._translateSpec(bucket);
		try {
			// Create the bucket, and wait until that has happened
			const response = await this._createBucket(bucket.metadata.name, attributes);

			// Apply all other operations
			// Note: These need to be await-ed separately, as we otherwise may hit "conflicting conditional operations", which won't be retried.
			await this._putBucketLogging(bucket.metadata.name, loggingParams);
			await this._putPublicAccessBlock(bucket, publicAccessBlockParams);
			if (sseParams) {
				await this._putBucketEncryption(bucket.metadata.name, sseParams);
			}

			return response;
		} catch (err) {
			if (err.name === 'BucketAlreadyOwnedByYou') {
				logger.info(`[${bucket.metadata.name}]: Bucket exists already and is owned by us, applying update instead`);
				return this.update(bucket);
			}

			throw err;
		}
	}

	/**
	 * Updates S3 bucket
	 *
	 * Creates a new bucket if it doesn't exists. Otherwise updates cause an error message.
	 *
	 * @param {Bucket} bucket Bucket definition in Kubernetes
	 * @return {Promise<any>} promise that resolves when the bucket is updated
	 */
	async update(bucket) {
		function isCompatibleBucketLocation(location, locationRequested) {
			if (location === locationRequested) {
				return true;
			}

			if (locationRequested === 'EU') {
				return location.startsWith('eu-');
			}

			return false;
		}

		const bucketName = bucket.metadata.name;
		try {
			const response = await this._headBucket(bucketName);

			// - location: Cannot be changed, so we should just check whether getBucketLocation returns the correct one
			const {attributes: {ACL, CreateBucketConfiguration = {LocationConstraint: 'us-west-1'}}, loggingParams, sseParams, publicAccessBlockParams} = this._translateSpec(bucket);
			const bucketLocation = await this._getBucketLocation(bucketName);
			if (!isCompatibleBucketLocation(bucketLocation.LocationConstraint, CreateBucketConfiguration.LocationConstraint)) {
				logger.error(`[${bucketName}]: Cannot update bucket location from ${bucketLocation} to ${CreateBucketConfiguration.locationConstraint}`);
				throw new Error('Invalid update: Cannot update bucket location');
			}

			// - acl, logging, Public Access Block, encryption: Overwrite it, letting AWS handle the problem of "update"
			// Note: These need to be await-ed separately, as we otherwise may hit "conflicting conditional operations", which won't be retried.
			await this._putBucketAcl(bucketName, {ACL});
			await this._putBucketLogging(bucketName, loggingParams);
			await this._putPublicAccessBlock(bucket, publicAccessBlockParams);
			if (sseParams) {
				await this._putBucketEncryption(bucket.metadata.name, sseParams);
			} else {
				await this._deleteBucketEncryption(bucket.metadata.name);
			}

			return response;
		} catch (err) {
			if (err.name === 'NotFound') {
				// Bucket doesn't exist: this means kubernetes saw an update, but in fact the bucket was never created,
				// or has been deleted in the meantime. Create it again.
				logger.info(`[${bucketName}]: Bucket does not/no longer exist, re-creating it`);
				return this.create(bucket);
			}

			throw err;
		}
	}

	/**
	 * Delete bucket
	 *
	 * @param {Bucket} bucket Bucket definition in Kubernetes
	 * @return {Promise<any>} a promise that resolves when the bucket was deleted
	 */
	delete(bucket) {
		return this._deleteBucket(bucket.metadata.name);
	}
}

module.exports = S3Bucket;
<commit_msg>Improve naming of temp variable<commit_after>const AWS = require('aws-sdk');

require('./kubernetes');
const {capitalize, capitalizeFieldNames, delay, isTransientNetworkError} = require('./utils');

const logger = require('log4js').getLogger('S3');

/**
 * A bucket resource in Kubernetes
 *
 * @typedef Bucket
 * @property {KubernetesMetadata} metadata
 * @property {BucketSpec} spec
 * @property {BucketStatus} [status]
 */

/**
 * A bucket specification
 *
 * @typedef BucketSpec
 * @property {("private"|"public-read"|"public-read-write"|"aws-exec-read"|"authenticated-read"|"bucket-owner-read"|"bucket-owner-full-control"|"log-delivery-write")} [acl] The canned ACL to apply to the bucket
 * @property {CreateBucketConfiguration} [createBucketConfiguration]
 * @property {LoggingConfiguration} [loggingConfiguration]
 * @property {BucketEncryption} [bucketEncryption] optional configuration for SSE
 */

/**
 * @typedef CreateBucketConfiguration
 * @property {("EU"|"eu-west-1"|"us-west-1"|"us-west-2"|"ap-south-1"|"ap-southeast-1"|"ap-southeast-2"|"ap-northeast-1"|"sa-east-1"|"cn-north-1"|"eu-central-1")} locationConstraint
 */

/**
 * Configuration of S3 bucket access logging.
 *
 * This structure is based on the definition in CloudFormation.
 *
 * @typedef LoggingConfiguration
 * @property {string} destinationBucketName
 * @property {string} logFilePrefix
 */

/**
 * A adapter for modifying AWS S3 buckets using Bucket definitions
 */
class S3Bucket { // eslint-disable-line padded-blocks
	/**
	 *
	 * @param {Object} [options] S3 client options
	 */
	constructor(options = {}) {
		this.s3 = new AWS.S3(options);
	}

	/**
	 * Translate the logging configuration into the 'logging params' for the AWS SDK.
	 *
	 * @param {string} bucketName the bucket name
	 * @param {LoggingConfiguration} loggingConfiguration logging configuration
	 * @returns {Object} the parameters for `putBucketLogging`
	 */
	_translateLoggingConfiguration(bucketName, loggingConfiguration) {
		let status;
		if (!loggingConfiguration) {
			status = {};
		} else {
			status = {
				LoggingEnabled: {
					TargetBucket: loggingConfiguration.destinationBucketName,
					TargetPrefix: loggingConfiguration.logFilePrefix,
				}
			};
		}

		return {
			Bucket: bucketName,
			BucketLoggingStatus: status
		};
	}

	/**
	 * Translate the logging configuration into the 'logging params' for the AWS SDK.
	 *
	 * @param {string} bucketName the bucket name
	 * @param {PublicAccessBlockConfiguration} publicAccessBlockConfiguration Public Access Block configuration
	 * @returns {Object} the parameters for `putPublicAccessBlock`
	 */
	_translatePublicAccessBlockConfiguration(bucketName, publicAccessBlockConfiguration) {
		let configuration;
		if (!publicAccessBlockConfiguration) {
			configuration = {};
		} else {
			configuration = {
				BlockPublicAcls: publicAccessBlockConfiguration.blockPublicAcls,
			};
		}

		return {
			Bucket: bucketName,
			PublicAccessBlockConfiguration: configuration
		};
	}

	/**
	 * Translate the SSE configuration into the 'server-side encryption params' for the AWS SDK.
	 *
	 * @param {string} bucketName the bucket name
	 * @param {BucketEncryption} bucketEncryption Bucket encryption (as per https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-bucketencryption.html)
	 * @returns {Object} the parameters for `putBucketEncryption`, or `null`
	 */
	_translateBucketEncryption(bucketName, bucketEncryption) {
		if (!bucketEncryption || !bucketEncryption.serverSideEncryptionConfiguration) {
			return null;
		}

		const rules = bucketEncryption.serverSideEncryptionConfiguration.map(rule => {
			// Determine the type of rule by looking at the keys in the rule
			// We need to do a case-insensitive comparison here!
			if (rule.serverSideEncryptionByDefault) {
				switch (rule.serverSideEncryptionByDefault.sseAlgorithm) {
				case 'AES256':
					// Sanity check: This will otherwise produce errors when applying the configuration
					if (rule.serverSideEncryptionByDefault.kmsMasterKeyId) {
						throw new Error('Unexpected kmsMasterKeyId in AES256 SSE configuration');
					}
					return {
						ApplyServerSideEncryptionByDefault: {
							SSEAlgorithm: rule.serverSideEncryptionByDefault.sseAlgorithm,
						},
					};
				case 'aws:kms':
					return {
						ApplyServerSideEncryptionByDefault: {
							KMSMasterKeyId: rule.serverSideEncryptionByDefault.kmsMasterKeyId,
							SSEAlgorithm: rule.serverSideEncryptionByDefault.sseAlgorithm,
						},
					};

				default:
					throw new Error(`Unsupported SSE algorithm ${rule.serverSideEncryptionByDefault.sseAlgorithm} for default encryption`);
				}
			}

			throw new Error(`Unsupport SSE rule with keys: ${Object.keys(rule)}`);
		});
		if (rules.length === 0) {
			// No rules: Assume no intent to configure default bucket encryption
			// This is different from "invalid rule"!
			return null;
		}

		return {
			Bucket: bucketName,
			ServerSideEncryptionConfiguration: {
				Rules: rules,
			},
		};
	}

	/**
	 * Convert the bucket.spec into parameters for the various AWS SDK operations.
	 *
	 * The resulting elements do not have the bucket name set.
	 *
	 * @param {Bucket} bucket a bucket definition
	 * @return {Object} the bucket attributes
	 */
	_translateSpec(bucket) {
		// Split the spec into parts
		const {loggingConfiguration, bucketEncryption, publicAccessBlockConfiguration, ...otherAttributes} = bucket.spec;
		const attributes = Object.keys(otherAttributes || {}).reduce((result, key) => {
			const value = bucket.spec[key];
			let resultKey;
			switch (key) {
			case 'acl':
				resultKey = key.toUpperCase();
				break;
			default:
				resultKey = capitalize(key);
				break;
			}
			// Convert to string
			const resultValue = capitalizeFieldNames(value);
			logger.debug(`[${bucket.metadata.name}]: Attribute ${key} = ${JSON.stringify(resultValue)}`);

			result[resultKey] = resultValue;
			return result;
		}, {});
		return {
			attributes,
			loggingParams: this._translateLoggingConfiguration(bucket.metadata.name, loggingConfiguration),
			publicAccessBlockParams: this._translatePublicAccessBlockConfiguration(bucket.metadata.name, publicAccessBlockConfiguration),
			sseParams: this._translateBucketEncryption(bucket.metadata.name, bucketEncryption),
		};
	}

	// XXX: logName could be awsOperation.name, except that that is empty for AWS?
	async _retryOnTransientNetworkErrors(logName, awsOperation, awsArguments) {
		const errorRetryDelay = 30000;
		try {
			return await awsOperation.apply(this.s3, awsArguments).promise();
		} catch (err) {
			if (isTransientNetworkError(err)) {
				logger.warn(`[${logName}]: transient ${err.code} ${err.errno}, retrying in ${errorRetryDelay / 1000}s`);
				await delay(errorRetryDelay);
				return this._retryOnTransientNetworkErrors(logName, awsOperation, awsArguments);
			}

			logger.warn(`[${logName}]: non-retryable error in operation: ${err.message}`);
			throw err;
		}
	}

	_reportError(logName, err, description) {
		logger.warn(`[${logName}]: ${description}: ${err.message}`);
		throw err;
	}

	async _createBucket(bucketName, attributes) {
		if (attributes.Bucket && attributes.Bucket !== bucketName) {
			throw new Error(`Inconsistent bucket name in configuration: ${bucketName} !== ${attributes.Bucket}`);
		}
		const request = Object.assign({}, attributes, {
			Bucket: bucketName
		});
		try {
			return await this._retryOnTransientNetworkErrors('S3::CreateBucket', this.s3.createBucket, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot create bucket');
		}
	}

	async _putBucketLogging(bucketName, loggingAttributes) {
		if (loggingAttributes.Bucket && loggingAttributes.Bucket !== bucketName) {
			throw new Error(`Inconsistent bucket name in configuration: ${bucketName} !== ${loggingAttributes.Bucket}`);
		}
		const request = Object.assign({}, loggingAttributes, {
			Bucket: bucketName
		});
		try {
			return await this._retryOnTransientNetworkErrors('S3::PutBucketLogging', this.s3.putBucketLogging, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot configure bucket logging');
		}
	}

	async _putBucketEncryption(bucketName, sseAttributes) {
		if (sseAttributes.Bucket && sseAttributes.Bucket !== bucketName) {
			throw new Error(`Inconsistent bucket name in configuration: ${bucketName} !== ${sseAttributes.Bucket}`);
		}
		const request = Object.assign({}, sseAttributes, {
			Bucket: bucketName
		});
		try {
			return await this._retryOnTransientNetworkErrors('S3::PutBucketEncryption', this.s3.putBucketEncryption, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot configure bucket encryption');
		}
	}

	async _putPublicAccessBlock(bucketName, publicAccessBlockParams) {
		if (publicAccessBlockParams.Bucket && publicAccessBlockParams.Bucket !== bucketName) {
			throw new Error(`Inconsistent bucket name in configuration: ${bucketName} !== ${publicAccessBlockParams.Bucket}`);
		}
		const request = Object.assign({}, publicAccessBlockParams, {
			Bucket: bucketName,
		});
		try {
			return await this._retryOnTransientNetworkErrors('S3::PutPublicAccessBlock', this.s3.putPublicAccessBlock, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot configure Block Public Access for bucket');
		}
	}

	async _putBucketAcl(bucketName, aclAttributes) {
		if (aclAttributes.Bucket && aclAttributes.Bucket !== bucketName) {
			throw new Error(`Inconsistent bucket name in configuration: ${bucketName} !== ${aclAttributes.Bucket}`);
		}
		const request = Object.assign({}, aclAttributes, {
			Bucket: bucketName
		});
		try {
			return await this._retryOnTransientNetworkErrors('S3::PutBucketAcl', this.s3.putBucketAcl, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot configure bucket ACL');
		}
	}

	async _deleteBucket(bucketName) {
		const request = {
			Bucket: bucketName
		};
		try {
			return await this._retryOnTransientNetworkErrors('S3::DeleteBucket', this.s3.deleteBucket, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot delete bucket');
		}
	}

	async _deleteBucketEncryption(bucketName) {
		const request = {
			Bucket: bucketName
		};
		try {
			return await this._retryOnTransientNetworkErrors('S3::DeleteBucketEncryption', this.s3.deleteBucketEncryption, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot remove bucket encryption');
		}
	}

	async _headBucket(bucketName) {
		const request = {
			Bucket: bucketName
		};
		try {
			return await this._retryOnTransientNetworkErrors('S3::HeadBucket', this.s3.headBucket, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot head bucket');
		}
	}

	async _getBucketLocation(bucketName) {
		const request = {
			Bucket: bucketName
		};
		try {
			return await this._retryOnTransientNetworkErrors('S3::GetBucketLocation', this.s3.getBucketLocation, [request]);
		} catch (err) {
			return this._reportError(bucketName, err, 'Cannot get bucket location');
		}
	}

	/**
	 * Create a new bucket
	 *
	 * @param {Bucket} bucket Bucket definition in Kubernetes
	 * @return {Promise<any>} promise that resolves when the bucket is created
	 */
	async create(bucket) {
		const {attributes, loggingParams, publicAccessBlockParams, sseParams} = this._translateSpec(bucket);
		try {
			// Create the bucket, and wait until that has happened
			const response = await this._createBucket(bucket.metadata.name, attributes);

			// Apply all other operations
			// Note: These need to be await-ed separately, as we otherwise may hit "conflicting conditional operations", which won't be retried.
			await this._putBucketLogging(bucket.metadata.name, loggingParams);
			await this._putPublicAccessBlock(bucket, publicAccessBlockParams);
			if (sseParams) {
				await this._putBucketEncryption(bucket.metadata.name, sseParams);
			}

			return response;
		} catch (err) {
			if (err.name === 'BucketAlreadyOwnedByYou') {
				logger.info(`[${bucket.metadata.name}]: Bucket exists already and is owned by us, applying update instead`);
				return this.update(bucket);
			}

			throw err;
		}
	}

	/**
	 * Updates S3 bucket
	 *
	 * Creates a new bucket if it doesn't exists. Otherwise updates cause an error message.
	 *
	 * @param {Bucket} bucket Bucket definition in Kubernetes
	 * @return {Promise<any>} promise that resolves when the bucket is updated
	 */
	async update(bucket) {
		function isCompatibleBucketLocation(location, locationRequested) {
			if (location === locationRequested) {
				return true;
			}

			if (locationRequested === 'EU') {
				return location.startsWith('eu-');
			}

			return false;
		}

		const bucketName = bucket.metadata.name;
		try {
			const response = await this._headBucket(bucketName);

			// - location: Cannot be changed, so we should just check whether getBucketLocation returns the correct one
			const {attributes: {ACL, CreateBucketConfiguration = {LocationConstraint: 'us-west-1'}}, loggingParams, sseParams, publicAccessBlockParams} = this._translateSpec(bucket);
			const bucketLocation = await this._getBucketLocation(bucketName);
			if (!isCompatibleBucketLocation(bucketLocation.LocationConstraint, CreateBucketConfiguration.LocationConstraint)) {
				logger.error(`[${bucketName}]: Cannot update bucket location from ${bucketLocation} to ${CreateBucketConfiguration.locationConstraint}`);
				throw new Error('Invalid update: Cannot update bucket location');
			}

			// - acl, logging, Public Access Block, encryption: Overwrite it, letting AWS handle the problem of "update"
			// Note: These need to be await-ed separately, as we otherwise may hit "conflicting conditional operations", which won't be retried.
			await this._putBucketAcl(bucketName, {ACL});
			await this._putBucketLogging(bucketName, loggingParams);
			await this._putPublicAccessBlock(bucket, publicAccessBlockParams);
			if (sseParams) {
				await this._putBucketEncryption(bucket.metadata.name, sseParams);
			} else {
				await this._deleteBucketEncryption(bucket.metadata.name);
			}

			return response;
		} catch (err) {
			if (err.name === 'NotFound') {
				// Bucket doesn't exist: this means kubernetes saw an update, but in fact the bucket was never created,
				// or has been deleted in the meantime. Create it again.
				logger.info(`[${bucketName}]: Bucket does not/no longer exist, re-creating it`);
				return this.create(bucket);
			}

			throw err;
		}
	}

	/**
	 * Delete bucket
	 *
	 * @param {Bucket} bucket Bucket definition in Kubernetes
	 * @return {Promise<any>} a promise that resolves when the bucket was deleted
	 */
	delete(bucket) {
		return this._deleteBucket(bucket.metadata.name);
	}
}

module.exports = S3Bucket;
<|endoftext|>


<commit_before>/*
Copyright 2018 New Vector Ltd

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.
*/

const request = require('request-promise-native');
const RestRoom = require('./room');
const {approveConsent} = require('./consent');

module.exports = class RestSession {
    constructor(credentials) {
        this.credentials = credentials;
    }

    _post(csApiPath, body) {
        return this._request("POST", csApiPath, body);
    }

    _put(csApiPath, body) {
        return this._request("PUT", csApiPath, body);
    }

    async _request(method, csApiPath, body) {
        try {
            const responseBody = await request({
                url: `${this.credentials.hsUrl}/_matrix/client/r0${csApiPath}`,
                method,
                headers: {
                    "Authorization": `Bearer ${this.credentials.accessToken}`
                },
                json: true,
                body
            });
            return responseBody;

        } catch(err) {
            const responseBody = err.response.body;
            if (responseBody.errcode === 'M_CONSENT_NOT_GIVEN') {
                await approveConsent(responseBody.consent_uri);
                return this._request(method, csApiPath, body);
            } else if(responseBody && responseBody.error) {
                throw new Error(`${method} ${csApiPath}: ${responseBody.error}`);
            } else {
                throw new Error(`${method} ${csApiPath}: ${err.response.statusCode}`);
            }
        }
    }

    async join(roomId) {
        const {room_id} = await this._post(`/rooms/${roomId}/join`);
        return new RestRoom(this, room_id);
    }

    async createRoom(name, options) {
        const body = {
            name,
        };
        if (options.invite) {
            body.invite = options.invite;
        }
        if (options.public) {
            body.visibility = "public";
        } else {
            body.visibility = "private";
        }
        if (options.dm) {
            body.is_direct = true;
        }
        if (options.topic) {
            body.topic = options.topic;
        }

        const {room_id} = await this._post(`/createRoom`, body);
        return new RestRoom(this, room_id);
    }
}
<commit_msg>support setting the display name on rest session<commit_after>/*
Copyright 2018 New Vector Ltd

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.
*/

const request = require('request-promise-native');
const RestRoom = require('./room');
const {approveConsent} = require('./consent');

module.exports = class RestSession {
    constructor(credentials) {
        this.credentials = credentials;
    }

    _post(csApiPath, body) {
        return this._request("POST", csApiPath, body);
    }

    _put(csApiPath, body) {
        return this._request("PUT", csApiPath, body);
    }

    async _request(method, csApiPath, body) {
        try {
            const responseBody = await request({
                url: `${this.credentials.hsUrl}/_matrix/client/r0${csApiPath}`,
                method,
                headers: {
                    "Authorization": `Bearer ${this.credentials.accessToken}`
                },
                json: true,
                body
            });
            return responseBody;

        } catch(err) {
            const responseBody = err.response.body;
            if (responseBody.errcode === 'M_CONSENT_NOT_GIVEN') {
                await approveConsent(responseBody.consent_uri);
                return this._request(method, csApiPath, body);
            } else if(responseBody && responseBody.error) {
                throw new Error(`${method} ${csApiPath}: ${responseBody.error}`);
            } else {
                throw new Error(`${method} ${csApiPath}: ${err.response.statusCode}`);
            }
        }
    }

    async setDisplayName(displayName) {
        await this._put(`/profile/${this.credentials.userId}/displayname`, {
            displayname: displayName
        });
    }

    async join(roomId) {
        const {room_id} = await this._post(`/rooms/${roomId}/join`);
        return new RestRoom(this, room_id);
    }

    async createRoom(name, options) {
        const body = {
            name,
        };
        if (options.invite) {
            body.invite = options.invite;
        }
        if (options.public) {
            body.visibility = "public";
        } else {
            body.visibility = "private";
        }
        if (options.dm) {
            body.is_direct = true;
        }
        if (options.topic) {
            body.topic = options.topic;
        }

        const {room_id} = await this._post(`/createRoom`, body);
        return new RestRoom(this, room_id);
    }
}
<|endoftext|>


<commit_before>"use strict";

var CityTour = CityTour || {};

CityTour.RoadIntersection = function(mapX, mapZ) {
  var edges = [];

  var indexOfEdge = function(mapX, mapZ) {
    var i;

    for (i = 0; i < edges.length; i++) {
      if (edges[i][0] === mapX && edges[i][1] === mapZ) {
        return i;
      }
    }

    return -1;
  };

  var roadIntersection = {};

  roadIntersection.addEdge = function(mapX, mapZ) {
    if (indexOfEdge(mapX, mapZ) === -1) {
      edges.push([mapX, mapZ]);
    }
  };

  roadIntersection.removeEdge = function(mapX, mapZ) {
    var index = indexOfEdge(mapX, mapZ);

    if (index !== -1) {
      edges.splice(index, 1);
    }
  };

  roadIntersection.hasPathTo = function(mapX, mapZ) {
    return indexOfEdge(mapX, mapZ) > -1;
  };

  roadIntersection.isEmpty = function() {
    return edges.length === 0;
  };

  return roadIntersection;
};

CityTour.BaseRoadNetwork = function() {
  var network = [];

  var roadNetwork = {};

  roadNetwork.hasIntersection = function(mapX, mapZ) {
    return network[[mapX, mapZ]] != null;
  };

  roadNetwork.setIntersectionAt = function(mapX, mapZ, roadIntersection) {
    network[[mapX, mapZ]] = roadIntersection;
  };

  roadNetwork.intersectionAt = function(mapX, mapZ) {
    return network[[mapX, mapZ]];
  };

  roadNetwork.hasEdgeBetween = function(mapX1, mapZ1, mapX2, mapZ2) {
    var roadIntersection1, roadIntersection2;

    roadIntersection1 = network[[mapX1, mapZ1]];
    roadIntersection2 = network[[mapX2, mapZ2]];

    return roadIntersection1 && roadIntersection2 &&
           roadIntersection1.hasPathTo(mapX2, mapZ2) && roadIntersection2.hasPathTo(mapX1, mapZ1);
  };

  return roadNetwork;
};

CityTour.AdditiveRoadNetwork = function(terrain, minColumn, maxColumn, minRow, maxRow) {
  var baseRoadNetwork = new CityTour.BaseRoadNetwork();

  var init = function() {
    var roadIntersection = new CityTour.RoadIntersection(0, 0);
    baseRoadNetwork.setIntersectionAt(0, 0, roadIntersection);
    branchFromIntersection(0, 0);
  };

  var calculateBlockProbabilityOfBranching = function(mapX, mapZ) {
    var PERCENTAGE_DISTANCE_THAT_DECAY_BEGINS = 0.4;

    var distanceToCityEdge = Math.min(CityTour.Config.HALF_BLOCK_COLUMNS, CityTour.Config.HALF_BLOCK_ROWS);
    var distanceFromCenter = Math.sqrt((mapX * mapX) + (mapZ * mapZ));
    var percentageFromCenter = (distanceFromCenter / distanceToCityEdge);
    var normalizedPercentageFromCenter;

    if (percentageFromCenter >= PERCENTAGE_DISTANCE_THAT_DECAY_BEGINS) {
      var safeFromDecayDistance = distanceToCityEdge * PERCENTAGE_DISTANCE_THAT_DECAY_BEGINS;
      normalizedPercentageFromCenter = (distanceFromCenter - safeFromDecayDistance) / (distanceToCityEdge - safeFromDecayDistance);
    }
    else {
      normalizedPercentageFromCenter = 0.0;
    }

    return (Math.pow(0.5, normalizedPercentageFromCenter) - 0.5) * 2;
  };

  var branchFromIntersection = function(mapX, mapZ) {
    var roadIntersection = baseRoadNetwork.intersectionAt(mapX, mapZ);

    connectIntersections(roadIntersection, mapX, mapZ, mapX - 1, mapZ);
    connectIntersections(roadIntersection, mapX, mapZ, mapX, mapZ - 1);
    connectIntersections(roadIntersection, mapX, mapZ, mapX + 1, mapZ);
    connectIntersections(roadIntersection, mapX, mapZ, mapX, mapZ + 1);
  };

  var isTerrainTooSteep = function(mapX, mapZ, targetMapX, targetMapZ) {
    var MAX_STEEPNESS = Math.PI / 6;

    var heightAtPoint1 = terrain.heightAtCoordinates(mapX, mapZ);
    var heightAtPoint2 = terrain.heightAtCoordinates(targetMapX, targetMapZ);
    var angle = Math.atan2((heightAtPoint1 - heightAtPoint2), CityTour.Config.BLOCK_DEPTH);

    return Math.abs(angle) > MAX_STEEPNESS;
  };

  var connectIntersections = function(roadIntersection, mapX, mapZ, targetMapX, targetMapZ) {
    var PROBABILITY = calculateBlockProbabilityOfBranching(mapX, mapZ);
    var random = Math.random();

    if (random < PROBABILITY && !isTerrainTooSteep(mapX, mapZ, targetMapX, targetMapZ)) {
      if (roadNetwork.hasIntersection(targetMapX, targetMapZ)) {
        roadIntersection.addEdge(targetMapX, targetMapZ);
        roadNetwork.intersectionAt(targetMapX, targetMapZ).addEdge(mapX, mapZ);
      }
      else {
        baseRoadNetwork.setIntersectionAt(targetMapX, targetMapZ, new CityTour.RoadIntersection(targetMapX, targetMapZ));
        roadIntersection.addEdge(targetMapX, targetMapZ);
        roadNetwork.intersectionAt(targetMapX, targetMapZ).addEdge(mapX, mapZ);
        branchFromIntersection(targetMapX, targetMapZ);
      }
    }
  };

  var roadNetwork = {};

  roadNetwork.hasIntersection = baseRoadNetwork.hasIntersection;
  roadNetwork.intersectionAt = baseRoadNetwork.intersectionAt;
  roadNetwork.hasEdgeBetween = baseRoadNetwork.hasEdgeBetween;

  init();

  return roadNetwork;
};
<commit_msg>Being more specific with variable names<commit_after>"use strict";

var CityTour = CityTour || {};

CityTour.RoadIntersection = function(mapX, mapZ) {
  var edges = [];

  var indexOfEdge = function(mapX, mapZ) {
    var i;

    for (i = 0; i < edges.length; i++) {
      if (edges[i][0] === mapX && edges[i][1] === mapZ) {
        return i;
      }
    }

    return -1;
  };

  var roadIntersection = {};

  roadIntersection.addEdge = function(mapX, mapZ) {
    if (indexOfEdge(mapX, mapZ) === -1) {
      edges.push([mapX, mapZ]);
    }
  };

  roadIntersection.removeEdge = function(mapX, mapZ) {
    var index = indexOfEdge(mapX, mapZ);

    if (index !== -1) {
      edges.splice(index, 1);
    }
  };

  roadIntersection.hasPathTo = function(mapX, mapZ) {
    return indexOfEdge(mapX, mapZ) > -1;
  };

  roadIntersection.isEmpty = function() {
    return edges.length === 0;
  };

  return roadIntersection;
};

CityTour.BaseRoadNetwork = function() {
  var network = [];

  var roadNetwork = {};

  roadNetwork.hasIntersection = function(mapX, mapZ) {
    return network[[mapX, mapZ]] != null;
  };

  roadNetwork.setIntersectionAt = function(mapX, mapZ, roadIntersection) {
    network[[mapX, mapZ]] = roadIntersection;
  };

  roadNetwork.intersectionAt = function(mapX, mapZ) {
    return network[[mapX, mapZ]];
  };

  roadNetwork.hasEdgeBetween = function(mapX1, mapZ1, mapX2, mapZ2) {
    var roadIntersection1, roadIntersection2;

    roadIntersection1 = network[[mapX1, mapZ1]];
    roadIntersection2 = network[[mapX2, mapZ2]];

    return roadIntersection1 && roadIntersection2 &&
           roadIntersection1.hasPathTo(mapX2, mapZ2) && roadIntersection2.hasPathTo(mapX1, mapZ1);
  };

  return roadNetwork;
};

CityTour.AdditiveRoadNetwork = function(terrain, minColumn, maxColumn, minRow, maxRow) {
  var baseRoadNetwork = new CityTour.BaseRoadNetwork();

  var init = function() {
    var roadIntersection = new CityTour.RoadIntersection(0, 0);
    baseRoadNetwork.setIntersectionAt(0, 0, roadIntersection);
    branchFromIntersection(0, 0);
  };

  var calculateBlockProbabilityOfBranching = function(mapX, mapZ) {
    var PERCENTAGE_DISTANCE_THAT_DECAY_BEGINS = 0.4;

    var distanceToCityEdge = Math.min(CityTour.Config.HALF_BLOCK_COLUMNS, CityTour.Config.HALF_BLOCK_ROWS);
    var distanceFromCenter = Math.sqrt((mapX * mapX) + (mapZ * mapZ));
    var percentageFromCenter = (distanceFromCenter / distanceToCityEdge);
    var normalizedPercentageFromCenter;

    if (percentageFromCenter >= PERCENTAGE_DISTANCE_THAT_DECAY_BEGINS) {
      var safeFromDecayDistance = distanceToCityEdge * PERCENTAGE_DISTANCE_THAT_DECAY_BEGINS;
      normalizedPercentageFromCenter = (distanceFromCenter - safeFromDecayDistance) / (distanceToCityEdge - safeFromDecayDistance);
    }
    else {
      normalizedPercentageFromCenter = 0.0;
    }

    return (Math.pow(0.5, normalizedPercentageFromCenter) - 0.5) * 2;
  };

  var branchFromIntersection = function(mapX, mapZ) {
    var roadIntersection = baseRoadNetwork.intersectionAt(mapX, mapZ);

    connectIntersections(roadIntersection, mapX, mapZ, mapX - 1, mapZ);
    connectIntersections(roadIntersection, mapX, mapZ, mapX, mapZ - 1);
    connectIntersections(roadIntersection, mapX, mapZ, mapX + 1, mapZ);
    connectIntersections(roadIntersection, mapX, mapZ, mapX, mapZ + 1);
  };

  var isTerrainTooSteep = function(mapX, mapZ, targetMapX, targetMapZ) {
    var MAX_STEEPNESS = Math.PI / 6;

    var heightAtPoint1 = terrain.heightAtCoordinates(mapX, mapZ);
    var heightAtPoint2 = terrain.heightAtCoordinates(targetMapX, targetMapZ);
    var angle = Math.atan2((heightAtPoint1 - heightAtPoint2), CityTour.Config.BLOCK_DEPTH);

    return Math.abs(angle) > MAX_STEEPNESS;
  };

  var connectIntersections = function(roadIntersection, mapX, mapZ, targetMapX, targetMapZ) {
    var PROBABILITY = calculateBlockProbabilityOfBranching(mapX, mapZ);
    var random = Math.random();

    if (random < PROBABILITY && !isTerrainTooSteep(mapX, mapZ, targetMapX, targetMapZ)) {
      if (baseRoadNetwork.hasIntersection(targetMapX, targetMapZ)) {
        roadIntersection.addEdge(targetMapX, targetMapZ);
        baseRoadNetwork.intersectionAt(targetMapX, targetMapZ).addEdge(mapX, mapZ);
      }
      else {
        baseRoadNetwork.setIntersectionAt(targetMapX, targetMapZ, new CityTour.RoadIntersection(targetMapX, targetMapZ));
        roadIntersection.addEdge(targetMapX, targetMapZ);
        baseRoadNetwork.intersectionAt(targetMapX, targetMapZ).addEdge(mapX, mapZ);
        branchFromIntersection(targetMapX, targetMapZ);
      }
    }
  };

  var additiveRoadNetwork = {};

  additiveRoadNetwork.hasIntersection = baseRoadNetwork.hasIntersection;
  additiveRoadNetwork.intersectionAt = baseRoadNetwork.intersectionAt;
  additiveRoadNetwork.hasEdgeBetween = baseRoadNetwork.hasEdgeBetween;

  init();

  return additiveRoadNetwork;
};
<|endoftext|>


<commit_before>var actions = require('actions')
var _ = require('lodash')

var roleAttacker = {
    run: function(creep) {
        if(creep.room.name != Game.flags.gotime.room.name) {
            creep.moveTo(Game.flags.gotime);
        } else {
            var target = creep.pos.findClosestByPath(FIND_HOSTILE_CREEPS);
            if(target == undefined) {
                target = creep.pos.findClosestByPath(FIND_HOSTILE_STRUCTURES, {
                    filter: (structure) => {
                        return structure.structureType != STRUCTURE_CONTROLLER;
                    }
                });
            }
            // the wall
            if(target == undefined) {
                target = creep.pos.findClosestByPath(FIND_STRUCTURES, {
                    filter: (structure) => {
                        return structureType == STRUCTURE_WALL;
                    }
                });
            }
            if(target != undefined) {
                if(creep.attack(target)) {
                    creep.moveTo(target);
                }
            }
	    }
    }
};

module.exports = roleAttacker;
<commit_msg>bugfix<commit_after>var actions = require('actions')
var _ = require('lodash')

var roleAttacker = {
    run: function(creep) {
        if(creep.room.name != Game.flags.gotime.pos.roomName) {
            creep.moveTo(Game.flags.gotime);
        } else {
            var target = creep.pos.findClosestByPath(FIND_HOSTILE_CREEPS);
            if(target == undefined) {
                target = creep.pos.findClosestByPath(FIND_HOSTILE_STRUCTURES, {
                    filter: (structure) => {
                        return structure.structureType != STRUCTURE_CONTROLLER;
                    }
                });
            }
            // the wall
            if(target == undefined) {
                target = creep.pos.findClosestByPath(FIND_STRUCTURES, {
                    filter: (structure) => {
                        return structureType == STRUCTURE_WALL;
                    }
                });
            }
            if(target != undefined) {
                if(creep.attack(target)) {
                    creep.moveTo(target);
                }
            }
	    }
    }
};

module.exports = roleAttacker;
<|endoftext|>


<commit_before>import Vue from 'vue';
import Router from 'vue-router';

import Home from '../components/Home';
import About from '../components/About';
import Help from '../components/Help';
import Machine from '../components/settings/Machine';
import Kit from '../components/settings/Kit';
import Container from '../components/settings/Container';
import Builder from '../components/tools/Builder';
import Main from '../components/Main';

Vue.use(Router);

const router = new Router({
  mode: 'history',
  scrollBehavior: () => ({ y: 0 }),
  routes: [
    { path: '/', component: Home },
    { path: '/about', component: About },
    {
      path: '/tools/builder',
      component: Main,
      children: [
        { path: '', component: Builder },
        { path: '/settings/machine', component: Machine },
        { path: '/settings/kits', component: Kit },
        { path: '/settings/containers/:type', component: Container },
      ],
    },
    { path: '/help', component: Help },

    { path: '*', redirect: '/' },
  ],
});

export default router;
<commit_msg>Fix the routing for the new Builder.vue and Summary.vue<commit_after>import Vue from 'vue';
import Router from 'vue-router';

import Home from '../components/Home';
import About from '../components/About';
import Help from '../components/Help';
import Machine from '../components/settings/Machine';
import Kit from '../components/settings/Kit';
import Container from '../components/settings/Container';
import Summary from '../components/summary/Summary';
import Builder from '../components/Builder';

Vue.use(Router);

const router = new Router({
  mode: 'history',
  scrollBehavior: () => ({ y: 0 }),
  routes: [
    { path: '/', component: Home },
    { path: '/about', component: About },
    {
      path: '/builder',
      component: Builder,
      children: [
        { path: '', component: Summary },
        { path: '/settings/machine', component: Machine },
        { path: '/settings/kits', component: Kit },
        { path: '/settings/containers/:type', component: Container },
      ],
    },
    { path: '/help', component: Help },

    { path: '*', redirect: '/' },
  ],
});

export default router;
<|endoftext|>


<commit_before>import Vue from 'vue'
import Router from 'vue-router'

const _import = require('./_import_' + process.env.NODE_ENV);
Vue.use(Router);
/* layout */
import Layout from '../views/layout/Layout.vue'

/**
 * icon : the icon show in the sidebar
 * hidden : if `hidden:true` will not show in the sidebar
 * redirect : if `redirect:noredirect` will no redirct in the levelbar
 * noDropdown : if `noDropdown:true` will has no submenu
 * meta : { role: ['admin'] }  will control the page role
 **/
export const constantRouterMap = [
  { path: '/login', component: _import('login/index'), hidden: true },
  { path: '/authredirect', component: _import('login/authredirect'), hidden: true },
  { path: '/404', component: _import('errorPage/404'), hidden: true },
  { path: '/401', component: _import('errorPage/401'), hidden: true },
  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    name: '首页',
    hidden: true,
    children: [
      { path: 'dashboard', component: _import('dashboard/index') }
    ]
  }, {
    path: '/introduction',
    component: Layout,
    redirect: '/introduction/index',
    icon: 'people',
    noDropdown: true,
    children: [{ path: 'index', component: _import('introduction/index'), name: '简述' }]
  }
];
export default new Router({
  // mode: 'history', //后端支持可开
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRouterMap
})
export const asyncRouterMap = [
  {
    path: '/permission',
    component: Layout,
    redirect: '/permission/index',
    name: '权限测试',
    icon: 'lock',
    meta: { role: ['admin'] },
    noDropdown: true,
    children: [{ path: 'index', component: _import('permission/index'), name: '权限测试页', meta: { role: ['admin'] } }]
  },
  {
    path: '/icon',
    component: Layout,
    icon: 'icon',
    noDropdown: true,
    children: [{ path: 'index', component: _import('svg-icons/index'), name: 'icons' }]
  },
  {
    path: '/components',
    component: Layout,
    redirect: '/components/index',
    name: '组件',
    icon: 'component',
    children: [
      { path: 'index', component: _import('components/index'), name: '介绍 ' },
      { path: 'tinymce', component: _import('components/tinymce'), name: '富文本编辑器' },
      { path: 'markdown', component: _import('components/markdown'), name: 'Markdown' },
      { path: 'jsoneditor', component: _import('components/jsonEditor'), name: 'JSON编辑器' },
      { path: 'dndlist', component: _import('components/dndList'), name: '列表拖拽' },
      { path: 'splitpane', component: _import('components/splitpane'), name: 'SplitPane' },
      { path: 'avatarupload', component: _import('components/avatarUpload'), name: '头像上传' },
      { path: 'dropzone', component: _import('components/dropzone'), name: 'Dropzone' },
      { path: 'sticky', component: _import('components/sticky'), name: 'Sticky' },
      { path: 'countto', component: _import('components/countTo'), name: 'CountTo' },
      { path: 'mixin', component: _import('components/mixin'), name: '小组件' },
      { path: 'backtotop', component: _import('components/backToTop'), name: '返回顶部' }
    ]
  },
  {
    path: '/charts',
    component: Layout,
    redirect: '/charts/index',
    name: '图表',
    icon: 'chart',
    children: [
      { path: 'index', component: _import('charts/index'), name: '介绍' },
      { path: 'keyboard', component: _import('charts/keyboard'), name: '键盘图表' },
      { path: 'keyboard2', component: _import('charts/keyboard2'), name: '键盘图表2' },
      { path: 'line', component: _import('charts/line'), name: '折线图' },
      { path: 'mixchart', component: _import('charts/mixChart'), name: '混合图表' }
    ]
  },
  {
    path: '/example',
    component: Layout,
    redirect: 'noredirect',
    name: '综合实例',
    icon: 'example',
    children: [
      {
        path: '/example/table',
        component: _import('example/table/index'),
        redirect: '/example/table/table',
        name: 'Table',
        icon: 'table',
        children: [
          { path: 'dynamictable', component: _import('example/table/dynamictable/index'), name: '动态table' },
          { path: 'dragtable', component: _import('example/table/dragTable'), name: '拖拽table' },
          { path: 'inline_edit_table', component: _import('example/table/inlineEditTable'), name: 'table内编辑' },
          { path: 'table', component: _import('example/table/table'), name: '综合table' }
        ]
      },
      { path: 'form/edit', icon: 'form', component: _import('example/form'), name: '编辑Form', meta: { isEdit: true } },
      { path: 'form/create', icon: 'form', component: _import('example/form'), name: '创建Form' },
      { path: 'tab/index', icon: 'tab', component: _import('example/tab/index'), name: 'Tab' }
    ]
  },
  {
    path: '/error',
    component: Layout,
    redirect: 'noredirect',
    name: '错误页面',
    icon: '404',
    children: [
      { path: '401', component: _import('errorPage/401'), name: '401' },
      { path: '404', component: _import('errorPage/404'), name: '404' }
    ]
  },
  {
    path: '/errlog',
    component: Layout,
    redirect: 'noredirect',
    name: 'errlog',
    icon: 'bug',
    noDropdown: true,
    children: [{ path: 'log', component: _import('errlog/index'), name: '错误日志' }]
  },
  {
    path: '/excel',
    component: Layout,
    redirect: '/excel/download',
    name: 'excel',
    icon: 'excel',
    children: [
      { path: 'download', component: _import('excel/index'), name: '导出excel' },
      { path: 'download2', component: _import('excel/selectExcel'), name: '导出已选择项' },
      { path: 'upload', component: _import('excel/uploadExcel'), name: 'upload excel' }
    ]
  },
  {
    path: '/theme',
    component: Layout,
    redirect: 'noredirect',
    name: 'theme',
    icon: 'theme',
    noDropdown: true,
    children: [{ path: 'index', component: _import('theme/index'), name: '换肤' }]
  },
  {
    path: '/clipboard',
    component: Layout,
    redirect: 'noredirect',
    icon: 'clipboard',
    noDropdown: true,
    children: [{ path: 'index', component: _import('clipboard/index'), name: 'clipboard' }]
  },
  { path: '*', redirect: '/404', hidden: true }
];
<commit_msg>add zip file<commit_after>import Vue from 'vue'
import Router from 'vue-router'

const _import = require('./_import_' + process.env.NODE_ENV);
Vue.use(Router);
/* layout */
import Layout from '../views/layout/Layout.vue'

/**
 * icon : the icon show in the sidebar
 * hidden : if `hidden:true` will not show in the sidebar
 * redirect : if `redirect:noredirect` will no redirct in the levelbar
 * noDropdown : if `noDropdown:true` will has no submenu
 * meta : { role: ['admin'] }  will control the page role
 **/
export const constantRouterMap = [
  {path: '/login', component: _import('login/index'), hidden: true},
  {path: '/authredirect', component: _import('login/authredirect'), hidden: true},
  {path: '/404', component: _import('errorPage/404'), hidden: true},
  {path: '/401', component: _import('errorPage/401'), hidden: true},
  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    name: '首页',
    hidden: true,
    children: [
      {path: 'dashboard', component: _import('dashboard/index')}
    ]
  }, {
    path: '/introduction',
    component: Layout,
    redirect: '/introduction/index',
    icon: 'people',
    noDropdown: true,
    children: [{path: 'index', component: _import('introduction/index'), name: '简述'}]
  }
];
export default new Router({
  // mode: 'history', //后端支持可开
  scrollBehavior: () => ({y: 0}),
  routes: constantRouterMap
})
export const asyncRouterMap = [
  {
    path: '/permission',
    component: Layout,
    redirect: '/permission/index',
    name: '权限测试',
    icon: 'lock',
    meta: {role: ['admin']},
    noDropdown: true,
    children: [{path: 'index', component: _import('permission/index'), name: '权限测试页', meta: {role: ['admin']}}]
  },
  {
    path: '/icon',
    component: Layout,
    icon: 'icon',
    noDropdown: true,
    children: [{path: 'index', component: _import('svg-icons/index'), name: 'icons'}]
  },
  {
    path: '/components',
    component: Layout,
    redirect: '/components/index',
    name: '组件',
    icon: 'component',
    children: [
      {path: 'index', component: _import('components/index'), name: '介绍 '},
      {path: 'tinymce', component: _import('components/tinymce'), name: '富文本编辑器'},
      {path: 'markdown', component: _import('components/markdown'), name: 'Markdown'},
      {path: 'jsoneditor', component: _import('components/jsonEditor'), name: 'JSON编辑器'},
      {path: 'dndlist', component: _import('components/dndList'), name: '列表拖拽'},
      {path: 'splitpane', component: _import('components/splitpane'), name: 'SplitPane'},
      {path: 'avatarupload', component: _import('components/avatarUpload'), name: '头像上传'},
      {path: 'dropzone', component: _import('components/dropzone'), name: 'Dropzone'},
      {path: 'sticky', component: _import('components/sticky'), name: 'Sticky'},
      {path: 'countto', component: _import('components/countTo'), name: 'CountTo'},
      {path: 'mixin', component: _import('components/mixin'), name: '小组件'},
      {path: 'backtotop', component: _import('components/backToTop'), name: '返回顶部'}
    ]
  },
  {
    path: '/charts',
    component: Layout,
    redirect: '/charts/index',
    name: '图表',
    icon: 'chart',
    children: [
      {path: 'index', component: _import('charts/index'), name: '介绍'},
      {path: 'keyboard', component: _import('charts/keyboard'), name: '键盘图表'},
      {path: 'keyboard2', component: _import('charts/keyboard2'), name: '键盘图表2'},
      {path: 'line', component: _import('charts/line'), name: '折线图'},
      {path: 'mixchart', component: _import('charts/mixChart'), name: '混合图表'}
    ]
  },
  {
    path: '/example',
    component: Layout,
    redirect: 'noredirect',
    name: '综合实例',
    icon: 'example',
    children: [
      {
        path: '/example/table',
        component: _import('example/table/index'),
        redirect: '/example/table/table',
        name: 'Table',
        icon: 'table',
        children: [
          {path: 'dynamictable', component: _import('example/table/dynamictable/index'), name: '动态table'},
          {path: 'dragtable', component: _import('example/table/dragTable'), name: '拖拽table'},
          {path: 'inline_edit_table', component: _import('example/table/inlineEditTable'), name: 'table内编辑'},
          {path: 'table', component: _import('example/table/table'), name: '综合table'}
        ]
      },
      {path: 'form/edit', icon: 'form', component: _import('example/form'), name: '编辑Form', meta: {isEdit: true}},
      {path: 'form/create', icon: 'form', component: _import('example/form'), name: '创建Form'},
      {path: 'tab/index', icon: 'tab', component: _import('example/tab/index'), name: 'Tab'}
    ]
  },
  {
    path: '/error',
    component: Layout,
    redirect: 'noredirect',
    name: '错误页面',
    icon: '404',
    children: [
      {path: '401', component: _import('errorPage/401'), name: '401'},
      {path: '404', component: _import('errorPage/404'), name: '404'}
    ]
  },
  {
    path: '/errlog',
    component: Layout,
    redirect: 'noredirect',
    name: 'errlog',
    icon: 'bug',
    noDropdown: true,
    children: [{path: 'log', component: _import('errlog/index'), name: '错误日志'}]
  },
  {
    path: '/excel',
    component: Layout,
    redirect: '/excel/download',
    name: 'excel',
    icon: 'excel',
    children: [
      {path: 'download', component: _import('excel/index'), name: '导出excel'},
      {path: 'download2', component: _import('excel/selectExcel'), name: '导出已选择项'},
      {path: 'upload', component: _import('excel/uploadExcel'), name: 'upload excel'}
    ]
  },
  {
    path: '/zip',
    component: Layout,
    redirect: '/zip/download',
    name: 'zip',
    icon: 'zip',
    children: [
      {path: 'download', component: _import('zip/index'), name: 'export zip'}
    ]
  },
  {
    path: '/theme',
    component: Layout,
    redirect: 'noredirect',
    name: 'theme',
    icon: 'theme',
    noDropdown: true,
    children: [{path: 'index', component: _import('theme/index'), name: '换肤'}]
  },
  {
    path: '/clipboard',
    component: Layout,
    redirect: 'noredirect',
    icon: 'clipboard',
    noDropdown: true,
    children: [{path: 'index', component: _import('clipboard/index'), name: 'clipboard'}]
  },
  {path: '*', redirect: '/404', hidden: true}
];
<|endoftext|>


<commit_before>/*
 * Description: Vue路由
 * User: zhaoyiming
 * Date: 2017/10/1
*/

import Vue from 'vue';
import Router from 'vue-router';
import Resource from 'vue-resource';

// 登录、注册、找回密码等
const accountIndex = () => import('@/components/account/index.vue');
const login = () => import('@/components/account/login.vue');
const regist = () => import('@/components/account/regist.vue');
const forgetPwdFirstStep = () => import('@/components/account/forgetpwd-firststep.vue');
const forgetPwdSecondStep = () => import('@/components/account/forgetpwd-secondstep.vue');

// 个人中心
const personal = () => import('@/components/personal/index.vue');

// 编辑个人信息
const personalEdit = () => import('@/components/personal/personal-edit.vue');
const changeUserHeadpic = () => import('@/components/personal/change-headpic.vue');
const changeUserName = () => import('@/components/personal/change-username.vue');
const changeUserSex = () => import('@/components/personal/change-usersex.vue');

// 首页
const globalCouponIndex = () => import('@/components/global-coupon/index.vue');

//全球优惠券列表页
const globalCouponList = () => import('@/components/global-coupon-list/index.vue');

// 领取优惠券
const getCoupon = () => import('@/components/get-coupon/index.vue');

Vue.use(Router);
Vue.use(Resource);

export default new Router({
	routes: [
		{
			path: '/',
			redirect: '/globalCouponIndex'
		},

		{
			path: '/accountIndex',
			name: 'AccountIndex',
			component: accountIndex,
			children: [
				{
					path: '/login',
					name: 'Login',
					component: login
				},
				{
					path: '/regist',
					name: 'Regist',
					component: regist
				}
			]
		},

		{
			path: '/forgetPwdFirstStep',
			name: 'ForgetPwdFirstStep',
			component: forgetPwdFirstStep
		 },
		 {
			path: '/forgetPwdSecondStep',
			name: 'ForgetPwdSecondStep',
			component: forgetPwdSecondStep
		 },

		{
			path: '/personal',
			name: 'Personal',
			component: personal
		},
		{
			path: '/personalEdit',
			name: 'PersonalEdit',
			component: personalEdit
		},
		{
			path: '/changeUserHeadpic/:userId/:headpic',
			name: 'ChangeUserHeadpic',
			component: changeUserHeadpic
		},
		{
			path: '/changeUserName/:userId/:userName',
			name: 'ChangeUserName',
			component: changeUserName
		},
		{
			path: '/changeUserSex/:userId/:userSex',
			name: 'ChangeUserSex',
			component: changeUserSex
		},

		{
			path: '/globalCouponIndex',
			name: 'GlobalCouponIndex',
			component: globalCouponIndex
		},

		{
			path: '/globalCouponList',
			name: 'GlobalCouponList',
			component: globalCouponList
		},

		{
			path: '/getCoupon/:couponId/:showType',
			name: 'GetCoupon',
			component: getCoupon
		}
	]
})
<commit_msg>隐藏url中的参数<commit_after>/*
 * Description: Vue路由
 * User: zhaoyiming
 * Date: 2017/10/1
*/

import Vue from 'vue';
import Router from 'vue-router';
import Resource from 'vue-resource';

// 登录、注册、找回密码等
const accountIndex = () => import('@/components/account/index.vue');
const login = () => import('@/components/account/login.vue');
const regist = () => import('@/components/account/regist.vue');
const forgetPwdFirstStep = () => import('@/components/account/forgetpwd-firststep.vue');
const forgetPwdSecondStep = () => import('@/components/account/forgetpwd-secondstep.vue');

// 个人中心
const personal = () => import('@/components/personal/index.vue');

// 编辑个人信息
const personalEdit = () => import('@/components/personal/personal-edit.vue');
const changeUserHeadpic = () => import('@/components/personal/change-headpic.vue');
const changeUserName = () => import('@/components/personal/change-username.vue');
const changeUserSex = () => import('@/components/personal/change-usersex.vue');

// 首页
const globalCouponIndex = () => import('@/components/global-coupon/index.vue');

//全球优惠券列表页
const globalCouponList = () => import('@/components/global-coupon-list/index.vue');

// 领取优惠券
const getCoupon = () => import('@/components/get-coupon/index.vue');

Vue.use(Router);
Vue.use(Resource);

export default new Router({
	routes: [
		{
			path: '/',
			redirect: '/globalCouponIndex'
		},

		{
			path: '/accountIndex',
			name: 'AccountIndex',
			component: accountIndex,
			children: [
				{
					path: '/login',
					name: 'Login',
					component: login
				},
				{
					path: '/regist',
					name: 'Regist',
					component: regist
				}
			]
		},

		{
			path: '/forgetPwdFirstStep',
			name: 'ForgetPwdFirstStep',
			component: forgetPwdFirstStep
		 },
		 {
			path: '/forgetPwdSecondStep',
			name: 'ForgetPwdSecondStep',
			component: forgetPwdSecondStep
		 },

		{
			path: '/personal',
			name: 'Personal',
			component: personal
		},
		{
			path: '/personalEdit',
			name: 'PersonalEdit',
			component: personalEdit
		},
		{
			path: '/changeUserHeadpic',
			name: 'ChangeUserHeadpic',
			component: changeUserHeadpic
		},
		{
			path: '/changeUserName',
			name: 'ChangeUserName',
			component: changeUserName
		},
		{
			path: '/changeUserSex',
			name: 'ChangeUserSex',
			component: changeUserSex
		},

		{
			path: '/globalCouponIndex',
			name: 'GlobalCouponIndex',
			component: globalCouponIndex
		},

		{
			path: '/globalCouponList',
			name: 'GlobalCouponList',
			component: globalCouponList
		},

		{
			path: '/getCoupon',
			name: 'GetCoupon',
			component: getCoupon
		}
	]
})
<|endoftext|>


<commit_before>import express from 'express';
import { logger } from '../services';

const router = new express.Router();
export default router;

function handleError(res) {
  return (error) => {
    // TODO implement more safe error handling
    logger.warn(error);
    res.status(error.code).send(error.message);
  };
}

const routes = [
  'home',
  'login',
  'login/callback',
  'token',
  'report/svg', // report/svg must place before repo/report.
  'repo',
  'repo/report',
];

routes.forEach(name => {
  const module = require(`./${name}`);
  const route = router.route(module.route);

  logger.debug(`[routes] route [${module.route}] from file [${name}] provides functions [${Object.keys(module)}].`);
  route.all((req, res, next) => {
    logger.debug(`[routes] request [${req.method}] path [${req.url}], hit route [${module.route}] from file [${name}].`);
    next();
  });

  if (module.post) {
    const middlewares = module.post.middlewares || [];
    route.post(
      ...middlewares,
      (req, res) =>
        module.post(req)
          .then(result =>
            // TODO leverage `res.format` to better content-negotiation
            req.accepts('html') === 'html'
            ? res.redirect(req.get('Referer'))
            : res.send(result))
          .catch(handleError(res)));
  }

  if (module.redirect) {
    route.get((req, res) =>
      module.redirect(req)
        .then(url => res.redirect(url)
        .catch(handleError(res))));
  } else if (module.view && module.model) {
    route.get((req, res) =>
      module.model(req)
        .then(model =>
          res.type(module.type || 'html').render(module.view, model))
        .catch(handleError(res)));
  } else {
    route.get((req, res) =>
      res.status(500).end());
  }
});
<commit_msg>Refine the route index logic.<commit_after>import express from 'express';
import { logger } from '../services';

function handleError(res) {
  return (error) => {
    // TODO implement more safe error handling
    logger.warn(error);
    res.status(error.code).send(error.message);
  };
}

function register(router, route, name, method) {
  return (middlewares = [], fn) => {
    router[method](route, ...middlewares, (req, res) => {
      logger.debug(`[routes] request [${method}] URL [${req.url}], hit route [${route}] from file [${name}].`);
      fn(req, res).catch(handleError(res));
    });
  };
}

function createRouter() {
  const router = new express.Router();

  const routes = [
    'home',
    'login',
    'login/callback',
    'token',
    'report/svg', // report/svg must place before repo/report.
    'repo',
    'repo/report',
  ];

  routes.forEach(name => {
    const module = require(`./${name}`);
    const get = register(router, module.route, name, 'get');
    const post = register(router, module.route, name, 'post');

    logger.debug(`[routes] route [${module.route}] from file [${name}] provides functions [${Object.keys(module)}].`);

    if (module.post) {
      post(module.post.middlewares, (req, res) =>
        module.post(req).then(result =>
          // TODO leverage `res.format` to better content-negotiation
          req.accepts('html') === 'html'
          ? res.redirect(req.get('Referer'))
          : res.send(result)));
    }

    if (module.redirect) {
      get(module.redirect.middlewares, (req, res) =>
        module.redirect(req).then(url => res.redirect(url)));
    } else if (module.view && module.model) {
      get(module.model.middlewares, (req, res) =>
        module.model(req).then(model =>
          res.type(module.type || 'html').render(module.view, model)));
    }
  });

  return router;
}

export default createRouter();
<|endoftext|>


<commit_before>const KoaRouter = require('koa-router');
const sendWelcomeEmail = require('../mailers/welcome');

const router = new KoaRouter();

router.get('usersNew', '/new', async ctx =>
  ctx.render('users/new', {
    user: ctx.orm.user.build(),
    createUserPath: ctx.router.url('usersCreate'),
  }),
);

router.post('usersCreate', '/', async (ctx) => {
  const user = ctx.orm.user.build(ctx.request.body);
  try {
    await user.save();
    ctx.flashMessage.notice = '¡Tu cuenta de usuario está lista para comenzar a usarla!';
    sendWelcomeEmail(ctx, { user });
    ctx.redirect(ctx.router.url('sessionNew'));
  } catch (validationError) {
    await ctx.render('users/new', {
      user,
      errors: validationError.errors,
      createUserPath: ctx.router.url('usersCreate'),
    });
  }
});

module.exports = router;
<commit_msg>Prevent creation of admin user by whitelisting allowed model attributes<commit_after>const KoaRouter = require('koa-router');
const sendWelcomeEmail = require('../mailers/welcome');

const router = new KoaRouter();

router.get('usersNew', '/new', async ctx =>
  ctx.render('users/new', {
    user: ctx.orm.user.build(),
    createUserPath: ctx.router.url('usersCreate'),
  }),
);

router.post('usersCreate', '/', async (ctx) => {
  const user = ctx.orm.user.build(ctx.request.body);
  try {
    await user.save({ fields: ['firstName', 'lastName', 'email', 'password'] });
    ctx.flashMessage.notice = '¡Tu cuenta de usuario está lista para comenzar a usarla!';
    sendWelcomeEmail(ctx, { user });
    ctx.redirect(ctx.router.url('sessionNew'));
  } catch (validationError) {
    await ctx.render('users/new', {
      user,
      errors: validationError.errors,
      createUserPath: ctx.router.url('usersCreate'),
    });
  }
});

module.exports = router;
<|endoftext|>


<commit_before>var main = document.getElementsByTagName('main')[0];
var images = main.getElementsByTagName('img');

function checkForUnveil() {
    var windowTop = window.scrollY;
    var windowBottom = windowTop + window.innerHeight;

    for (var i = 0; i < images.length; i++) {
        var image = images[i];

        var elementTop = image.getBoundingClientRect().top;
        var elementBottom = elementTop + image.offsetHeight;

        if (elementBottom >= windowTop - 200 && elementTop <= windowBottom + 200) {
            var event = document.createEvent('HTMLEvents');
            event.initEvent('unveil', true, false);
            image.dispatchEvent(event);
        }
    }
}

function unveil(event) {
    var image = event.currentTarget;
    image.onload = function(event) {
        var second = new Image();
        second.src = event.currentTarget.getAttribute('data-src-second');
    };

    image.setAttribute('src', image.getAttribute('data-src'));

    image.removeEventListener('unveil', unveil);
}

function valse(event) {
    var image = event.currentTarget;
    var source = event.type === 'mousedown' || event.type === 'touchstart' ? image.getAttribute('data-src-second') : image.getAttribute('data-src');

    image.setAttribute('src', source);
}

for (var i = 0; i < images.length; i++) {
    images[i].addEventListener('unveil', unveil);
    images[i].addEventListener('mousedown', valse);
    images[i].addEventListener('mouseleave', valse);
    images[i].addEventListener('mouseup', valse);
    images[i].addEventListener('touchstart', valse);
    images[i].addEventListener('touchleave', valse);
    images[i].addEventListener('touchend', valse);
}

window.onscroll = checkForUnveil;
window.onresize = checkForUnveil;

checkForUnveil();
<commit_msg>Improving image unveil event binding<commit_after>var mainElement = document.querySelector('main');

function checkForUnveil() {
    var windowTop = window.scrollY;
    var windowBottom = windowTop + window.innerHeight;
    var images = document.querySelectorAll('main img');

    for (var i = 0; i < images.length; i++) {
        var image = images[i];

        var elementTop = image.getBoundingClientRect().top;
        var elementBottom = elementTop + image.offsetHeight;

        if (elementBottom >= windowTop - 200 && elementTop <= windowBottom + 200) {
            var event = document.createEvent('HTMLEvents');
            event.initEvent('unveil', true, false);
            image.dispatchEvent(event);
        }
    }
}

function unveil(event) {
    var image = event.target || event.toElement;

    image.onload = function(event) {
        var second = new Image();
        second.src = event.currentTarget.getAttribute('data-src-second');
    };

    image.setAttribute('src', image.getAttribute('data-src'));

    image.removeEventListener('unveil', unveil);
}

mainElement.addEventListener('unveil', unveil);
function valse(event) {
    var image = event.currentTarget;
    var source = event.type === 'mousedown' || event.type === 'touchstart' ? image.getAttribute('data-src-second') : image.getAttribute('data-src');

    image.setAttribute('src', source);
}

for (var i = 0; i < images.length; i++) {
    images[i].addEventListener('unveil', unveil);
    images[i].addEventListener('mousedown', valse);
    images[i].addEventListener('mouseleave', valse);
    images[i].addEventListener('mouseup', valse);
    images[i].addEventListener('touchstart', valse);
    images[i].addEventListener('touchleave', valse);
    images[i].addEventListener('touchend', valse);
}

window.onscroll = checkForUnveil;
window.onresize = checkForUnveil;

checkForUnveil();
<|endoftext|>


<commit_before>(function(tiy, $) {
    'use strict';

    // Public API methods
    tiy.loadModule = loadModule;

    // locals & constants
    let tiyoData = null;
    let navUI = null;
    let mainUI = null;
    let modulesLoaded = [];
    let moduleDisplayed = null;
    let dataLoaded = false;
    let uiLoaded = false;

    const MAIN_TEMPLATE = 'build/templates/main.html';
    const NAV_TEMPLATE = 'build/templates/nav.html';
    const PANEL_ANIMATION_TIME = 200;

    function main() {
        console.info('Initializing TIYO assistant');

        addFontAwesomeStyleSheet();

        collectData()
        .then(function getNavUI(data) {
            tiyoData = data;
            dataLoaded = true;
            console.log('Data gathered', data);
            return $.get(chrome.extension.getURL(NAV_TEMPLATE));
        })
        .then(function getMainUI(html) {
            navUI = $(html);
            $('.main .header:first').append(navUI);

            modulesLoaded.forEach(addNavIcon);
            navUI.on('click', 'li', toggleModuleUI);

            return $.get(chrome.extension.getURL(MAIN_TEMPLATE));
        })
        .then(function callModuleRenders(html) {
            mainUI = $(html);
            $('.main .content').prepend(mainUI);
            uiLoaded = true;

            setupContentClose();

            console.log('UI base loaded, calling render methods', mainUI);
            modulesLoaded.forEach(function(mod) {
                doRender(mod);
            });
        });
    }

    /**
    * Chrome extensions have issues with access files from css like fonts, so
    * we need to embed the styelsheet using the chromse extension URL, which
    * is dynamically generated. The remainder of the FA styles are in a static
    * stylesheet in /vendor
    */
    function addFontAwesomeStyleSheet() {
        $('head').append(
            $('<style>')
            .attr('type', 'text/css')
            .text(
                `@font-face {
                    font-family: FontAwesome;
                    src: url('${chrome.extension.getURL('vendor/fontawesome-webfont.woff')}');
                }`
            )
        );
    }

    function getUser() {
        try {
            return  JSON.parse(
                $( "#IntercomSettingsScriptTag" )
                .text()
                .replace("window.intercomSettings =", "")
                .replace(";", "")
            );
        } catch (e) {
            return;
        }
    }

    function collectData() {
        let pathname = window.location.pathname.split(/\//),
            data = {
                user: null,
                path: null,
                content: null,
                group: null,
                students: []
            },
            group = $('.card-block dt:contains("Group")').next().find('a');

        data.user = getUser();

        if (pathname.length === 4 && pathname[2] === 'paths') {
            data.path = {
                id: Number(pathname[3]),
                title: $('.content .breadcrumb li:eq(1)').text()
            };
        }

        if (pathname.length > 3 && (pathname[2] === 'lessons' || pathname[2] === 'assignments')) {
            data.content = {
                id: Number(pathname[3]),
                title: $('.content .breadcrumb li:eq(3)').text(),
                type: pathname[2]
            };
        }

        let p;
        if (group.length) {
            data.group = {
                title: group.text(),
                id: Number(group.attr('href').match(/\/([0-9]+)/)[1])
            };

            p = $.get(group.attr('href')).then(function(html) {
                let students = $(html).find('#students tr td:first-child a');
                students.each(function() {
                    let studentElem = $(this).find('.profile-placeholder-medium, img').remove().end();
                    data.students.push({
                        id: Number(studentElem.attr('href').match(/\/([0-9]+)/)[1]),
                        name: studentElem.text()
                    });
                });
                return data;
            });
        } else {
            p = Promise.resolve(data);
        }

        return p;
    }

    function addNavIcon(mod) {
        if (!navUI) { return; }

        navUI.find('ul').append(
            `<li data-module='${mod.name}' title='${mod.name}' aria-title='${mod.name}'><i class='fa ${mod.navIcon} fa-lg' aria-hidden='true'></i></li>`
        );
    }

    function toggleModuleUI(e) {
        e.preventDefault();
        var name = $(this).data('module');
        var mod = modulesLoaded.filter(function(m) { return m.name === name;});
        if (!mod.length) { return; }

        if (moduleDisplayed === mod[0].name) {
            console.log('hiding ', mod[0]);
            closeContent(e);
        } else {
            console.log('showing ', mod[0]);
            moduleDisplayed = mod[0].name;
            $('.tiyo-assistant-module').hide();
            $(`[data-module="${mod[0].name}"]`).show().trigger('showing');
            mainUI.slideDown(PANEL_ANIMATION_TIME);
        }
    }

    function closeContent(e) {
        e.preventDefault();
        $(`[data-module="${moduleDisplayed}"]`).show().trigger('hiding');
        moduleDisplayed = null;
        mainUI.slideUp(PANEL_ANIMATION_TIME);
    }

    function setupContentClose() {
        $('.tiyo-assistant-close').click(closeContent);
    }

    function loadModule(api) {
        if (!api) { return; }
        if (!api.name) { api.name = Date.getTime(); }

        console.info('loading module', api);

        modulesLoaded.push(api);

        addNavIcon(api);
        doRender(api);
    }

    function doRender(mod) {
        if (uiLoaded && typeof(mod.render) === 'function') {
            var elem = createModuleWrapper(mod);
            mod.render(tiyoData, elem);
        }
    }

    function createModuleWrapper(mod) {
        var elem = $(`<article data-module='${mod.name}'>`).addClass('tiyo-assistant-module');
        $(mainUI).find('.tiyo-assistant-content').append(elem);
        return elem;
    }

    // Kick things off...
    main();
    // Then export our module API
    window.tiy = tiy;

})(window.tiy || {}, window.jQuery);
<commit_msg>Added 'edit' flag for page data<commit_after>(function(tiy, $) {
    'use strict';

    // Public API methods
    tiy.loadModule = loadModule;

    // locals & constants
    let tiyoData = null;
    let navUI = null;
    let mainUI = null;
    let modulesLoaded = [];
    let moduleDisplayed = null;
    let dataLoaded = false;
    let uiLoaded = false;

    const MAIN_TEMPLATE = 'build/templates/main.html';
    const NAV_TEMPLATE = 'build/templates/nav.html';
    const PANEL_ANIMATION_TIME = 200;

    function main() {
        console.info('Initializing TIYO assistant');

        addFontAwesomeStyleSheet();

        collectData()
        .then(function getNavUI(data) {
            tiyoData = data;
            dataLoaded = true;
            console.log('Data gathered', data);
            return $.get(chrome.extension.getURL(NAV_TEMPLATE));
        })
        .then(function getMainUI(html) {
            navUI = $(html);
            $('.main .header:first').append(navUI);

            modulesLoaded.forEach(addNavIcon);
            navUI.on('click', 'li', toggleModuleUI);

            return $.get(chrome.extension.getURL(MAIN_TEMPLATE));
        })
        .then(function callModuleRenders(html) {
            mainUI = $(html);
            $('.main .content').prepend(mainUI);
            uiLoaded = true;

            setupContentClose();

            console.log('UI base loaded, calling render methods', mainUI);
            modulesLoaded.forEach(function(mod) {
                doRender(mod);
            });
        });
    }

    /**
    * Chrome extensions have issues with access files from css like fonts, so
    * we need to embed the styelsheet using the chromse extension URL, which
    * is dynamically generated. The remainder of the FA styles are in a static
    * stylesheet in /vendor
    */
    function addFontAwesomeStyleSheet() {
        $('head').append(
            $('<style>')
            .attr('type', 'text/css')
            .text(
                `@font-face {
                    font-family: FontAwesome;
                    src: url('${chrome.extension.getURL('vendor/fontawesome-webfont.woff')}');
                }`
            )
        );
    }

    function getUser() {
        try {
            return  JSON.parse(
                $( "#IntercomSettingsScriptTag" )
                .text()
                .replace("window.intercomSettings =", "")
                .replace(";", "")
            );
        } catch (e) {
            return;
        }
    }

    function collectData() {
        let pathname = window.location.pathname.split(/\//),
            data = {
                user: null,
                path: null,
                content: null,
                group: null,
                students: []
            },
            group = $('.card-block dt:contains("Group")').next().find('a');

        data.user = getUser();

        if (pathname.length === 4 && pathname[2] === 'paths') {
            data.path = {
                id: Number(pathname[3]),
                title: $('.content .breadcrumb li:eq(1)').text()
            };
        } else if (pathname.length === 4 && pathname[1] === 'paths') {
            data.path = {
                id: Number(pathname[2]),
                title: $('.m-pathheader-info-title').text()
            };
        }

        if (pathname.length > 3 && (pathname[2] === 'lessons' || pathname[2] === 'assignments')) {
            data.content = {
                id: Number(pathname[3]),
                title: $('.content .breadcrumb li:eq(3)').text(),
                type: pathname[2],
                isEdit: true
            };
        } else if (/paths\/[0-9]+\/units\/[0-9]+\/[^\/]+\/[0-9]+/.test(window.location.pathname)) {
            data.content = {
                id: Number(pathname[6]),
                title: $('.m-lessonheader-title').text(),
                type: pathname[5],
                isEdit: false
            };
        }

        let p;
        if (group.length) {
            data.group = {
                title: group.text(),
                id: Number(group.attr('href').match(/\/([0-9]+)/)[1])
            };

            p = $.get(group.attr('href')).then(function(html) {
                let students = $(html).find('#students tr td:first-child a');
                students.each(function() {
                    let studentElem = $(this).find('.profile-placeholder-medium, img').remove().end();
                    data.students.push({
                        id: Number(studentElem.attr('href').match(/\/([0-9]+)/)[1]),
                        name: studentElem.text()
                    });
                });
                return data;
            });
        } else {
            p = Promise.resolve(data);
        }

        return p;
    }

    function addNavIcon(mod) {
        if (!navUI) { return; }

        navUI.find('ul').append(
            `<li data-module='${mod.name}' title='${mod.name}' aria-title='${mod.name}'><i class='fa ${mod.navIcon} fa-lg' aria-hidden='true'></i></li>`
        );
    }

    function toggleModuleUI(e) {
        e.preventDefault();
        var name = $(this).data('module');
        var mod = modulesLoaded.filter(function(m) { return m.name === name;});
        if (!mod.length) { return; }

        if (moduleDisplayed === mod[0].name) {
            console.log('hiding ', mod[0]);
            closeContent(e);
        } else {
            console.log('showing ', mod[0]);
            moduleDisplayed = mod[0].name;
            $('.tiyo-assistant-module').hide();
            $(`[data-module="${mod[0].name}"]`).show().trigger('showing');
            mainUI.slideDown(PANEL_ANIMATION_TIME);
        }
    }

    function closeContent(e) {
        e.preventDefault();
        $(`[data-module="${moduleDisplayed}"]`).show().trigger('hiding');
        moduleDisplayed = null;
        mainUI.slideUp(PANEL_ANIMATION_TIME);
    }

    function setupContentClose() {
        $('.tiyo-assistant-close').click(closeContent);
    }

    function loadModule(api) {
        if (!api) { return; }
        if (!api.name) { api.name = Date.getTime(); }

        console.info('loading module', api);

        modulesLoaded.push(api);

        addNavIcon(api);
        doRender(api);
    }

    function doRender(mod) {
        if (uiLoaded && typeof(mod.render) === 'function') {
            var elem = createModuleWrapper(mod);
            mod.render(tiyoData, elem);
        }
    }

    function createModuleWrapper(mod) {
        var elem = $(`<article data-module='${mod.name}'>`).addClass('tiyo-assistant-module');
        $(mainUI).find('.tiyo-assistant-content').append(elem);
        return elem;
    }

    // Kick things off...
    main();
    // Then export our module API
    window.tiy = tiy;

})(window.tiy || {}, window.jQuery);
<|endoftext|>