<commit_before>var five = require("johnny-five"),
    Edison = require("edison-io"),
    board = new five.Board({
        io: new Edison()
    }),
    express = require("express"),
    app = express(),
    server = app.listen(3000);

app.use(express.static('public'));

board.on("ready", function() {
  var rightServo = new five.Servo.Continuous(5),
      leftServo = new five.Servo.Continuous(6),
      led = new five.Led(13),
      piezo = new five.Piezo(3),
      la_cucaracha = '- - C C - C C - C C - F F F F - A A A A - -';

  // Add to REPL
  this.repl.inject({
    led: led,
    rightServo: rightServo,
    leftServo: leftServo,
    piezo: piezo
  });

  app.post('/forward', function(sReq, sRes){
    led.blink();

    rightServo.cw(1);
    leftServo.ccw(1);

    sRes.end();
  });

  app.post('/backward', function(sReq, sRes){
    led.blink();

    rightServo.ccw(1);
    leftServo.cw(1);

    sRes.end();
  });

  app.post('/right', function(sReq, sRes){
    led.blink();

    rightServo.ccw(0.5);
    leftServo.ccw(0.5);

    sRes.end();
  });

  app.post('/left', function(sReq, sRes){
    led.blink();

    rightServo.cw(0.5);
    leftServo.cw(0.5);

    sRes.end();
  });

  app.post('/stop', function(sReq, sRes){
    led.blink();

    rightServo.cw(0);
    leftServo.cw(0);

    sRes.end();
  });

  app.post('/honk', function(sReq, sRes){
    led.blink();

    piezo.play({
        // song is composed by a string of notes
        // a default beat is set, and the default octave is used
        // any invalid note is read as "no note"
        song: la_cucaracha + la_cucaracha,
        beats: 1 / 8,
        tempo: 100
    });

    sRes.end();
  });
});<commit_msg>add photoresistor<commit_after>var five = require("johnny-five"),
    Edison = require("edison-io"),
    board = new five.Board({
        io: new Edison()
    }),
    express = require("express"),
    app = express(),
    server = app.listen(3000);

app.use(express.static('public'));

board.on("ready", function() {
  var rightServo = new five.Servo.Continuous(5),
      leftServo = new five.Servo.Continuous(6),
      led = new five.Led(13),
      piezo = new five.Piezo(3),
      la_cucaracha = '- - C C - C C - C C - F F F F - A A A A - -',
      photoresistor = new five.Sensor({
        pin: "A2",
        freq: 250
      });

  // "data" get the current reading from the photoresistor
  photoresistor.on("data", function() {
    console.log(this.value);
  });

  // Add to REPL
  this.repl.inject({
    led: led,
    rightServo: rightServo,
    leftServo: leftServo,
    piezo: piezo,
    pot: photoresistor
  });

  app.post('/forward', function(sReq, sRes){
    led.blink();

    rightServo.cw(1);
    leftServo.ccw(1);

    sRes.end();
  });

  app.post('/backward', function(sReq, sRes){
    led.blink();

    rightServo.ccw(1);
    leftServo.cw(1);

    sRes.end();
  });

  app.post('/right', function(sReq, sRes){
    led.blink();

    rightServo.ccw(0.5);
    leftServo.ccw(0.5);

    sRes.end();
  });

  app.post('/left', function(sReq, sRes){
    led.blink();

    rightServo.cw(0.5);
    leftServo.cw(0.5);

    sRes.end();
  });

  app.post('/stop', function(sReq, sRes){
    led.blink();

    rightServo.cw(0);
    leftServo.cw(0);

    sRes.end();
  });

  app.post('/honk', function(sReq, sRes){
    led.blink();

    piezo.play({
        // song is composed by a string of notes
        // a default beat is set, and the default octave is used
        // any invalid note is read as "no note"
        song: la_cucaracha + la_cucaracha,
        beats: 1 / 8,
        tempo: 100
    });

    sRes.end();
  });
});<|endoftext|>


<commit_before>import 'es6-promise/auto';
import { createStore, applyMiddleware, compose } from 'redux';
import { setOption } from './actions/options';
import { editActive, editInactive } from './actions/editable';
import { login, logout } from './actions/authentication';
import { get, set, remove, find } from './actions/data';
import { observeQuery } from './actions/queries';
import save from './actions/save';
import { AUTH_SERVER } from './constants/options';
import { DATA_PREFIX, QUERIES_PREFIX, PUBLIC_STATE_MAP } from './constants/state';
import * as types from './constants/actionTypes';
import { configurePolymer } from './utils/prepare';
import {
  storeToObserver,
  dispatchThunkAndExpect,
  pathToUid,
  selectPropByPath,
  itemUidToPath,
  queryResultsToPath,
  validatePath,
  toQueryParams,
  uidsToResponse,
  clone
} from './utils/helpers';
import ping from './plugins/ping';
import persistToken from './plugins/persistToken';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

// Setup Polymer configuration
configurePolymer();

const Simpla = new class Simpla {
  constructor() {
    const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
    this._store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunk)));
  }

  init(project) {
    this._store.dispatch(setOption('project', project));

    // Initialize endpoints
    this._store.dispatch(setOption('authEndpoint', AUTH_SERVER));
    this._store.dispatch(setOption('dataEndpoint', `${AUTH_SERVER}/projects/${project}/content`));
  }

  // Authentication
  login(...args) {
    return dispatchThunkAndExpect(this._store, login(...args), types.LOGIN_SUCCESSFUL);
  }

  logout(...args) {
    return dispatchThunkAndExpect(this._store, logout(...args), types.LOGOUT_SUCCESSFUL);
  }

  // Data
  find(options = {}) {
    let parentPath = options.parent,
        ancestorPath = options.ancestor;

    if (parentPath) {
      options.parent = pathToUid(parentPath);
    }

    if (ancestorPath) {
      options.ancestor = pathToUid(ancestorPath);
    }

    return Promise.resolve()
      .then(() => {
        if (parentPath) {
          validatePath(parentPath);
        }

        if (ancestorPath) {
          validatePath(ancestorPath);
        }
      })
      .then(() => dispatchThunkAndExpect(
        this._store,
        find(options),
        types.FIND_DATA_SUCCESSFUL
      ))
      .then(queryResultsToPath)
      .then(clone);
  }

  get(path, ...args) {
    const uid = pathToUid(path);
    return Promise.resolve()
      .then(() => validatePath(path))
      .then(() => dispatchThunkAndExpect(
        this._store,
        get(uid, ...args),
        types.GET_DATA_SUCCESSFUL
      ))
      .then(itemUidToPath)
      .then(clone);
  }

  set(path, ...args) {
    const uid = pathToUid(path);
    return Promise.resolve()
      .then(() => validatePath(path))
      .then(() => dispatchThunkAndExpect(
        this._store,
        set(uid, ...args),
        types.SET_DATA_SUCCESSFUL
      ))
      .then(itemUidToPath);
  }

  remove(path, ...args) {
    const uid = pathToUid(path);
    return Promise.resolve()
      .then(() => validatePath(path))
      .then(() => dispatchThunkAndExpect(
        this._store,
        remove(uid, ...args),
        types.REMOVE_DATA_SUCCESSFUL
      ))
      .then(itemUidToPath);
  }

  observe(path, ...args) {
    let callback = args.pop(),
        uid = pathToUid(path),
        pathInState,
        wrappedCallback;

    if (!uid) {
      throw new Error('Observe must be given a valid path');
    }

    validatePath(path);

    pathInState = [ DATA_PREFIX, 'content', uid ];
    wrappedCallback = () => this.get(path).then(callback);

    return storeToObserver(this._store).observe(pathInState, wrappedCallback);
  }

  observeQuery(query, callback) {
    let queryString,
        pathInStore,
        wrappedCallback;

    // Clone so as to not affect given param
    query = Object.assign({}, query);

    query.parent = pathToUid(query.parent);
    queryString = toQueryParams(query);
    pathInStore = [ QUERIES_PREFIX, queryString, 'matches' ];

    this._store.dispatch(observeQuery(query));

    wrappedCallback = (uids) => {
      return callback(
        queryResultsToPath(
          clone(uidsToResponse(uids, this._store.getState()))
        )
      );
    }

    return storeToObserver(this._store).observe(pathInStore, wrappedCallback);
  }

  prefetch(path) {
    return this.find({ ancestor: path });
  }

  save(...args) {
    return dispatchThunkAndExpect(this._store, save(...args), types.SAVE_SUCCESSFUL);
  }

  // Editable
  editable(on) {
    this._store.dispatch(on ? editActive() : editInactive());
  }

  // State
  getState(substate) {
    let state = this._store.getState();

    if (substate) {
      let path = PUBLIC_STATE_MAP[substate];
      return path ? selectPropByPath(path, state) : undefined;
    }

    return Object.keys(PUBLIC_STATE_MAP).reduce((publicState, property) => {
      let path = PUBLIC_STATE_MAP[property];
      return Object.assign(
        publicState,
        { [ property ]: selectPropByPath(path, state) }
      );
    }, {});
  }

  observeState(substate, callback) {
    if (!substate) {
      throw new Error('No state given. Must include a state to observe e.g. Simpla.observeState(\'authenticated\', showAdmin)');
    }

    let realSubstate = PUBLIC_STATE_MAP[substate];
    return storeToObserver(this._store).observe(realSubstate, callback);
  }
}

// Init plugins
const plugins = [
  ping,
  persistToken
];

plugins.forEach(plugin => plugin(Simpla));

export default Simpla;
<commit_msg>prefetch should resolve to nothing<commit_after>import 'es6-promise/auto';
import { createStore, applyMiddleware, compose } from 'redux';
import { setOption } from './actions/options';
import { editActive, editInactive } from './actions/editable';
import { login, logout } from './actions/authentication';
import { get, set, remove, find } from './actions/data';
import { observeQuery } from './actions/queries';
import save from './actions/save';
import { AUTH_SERVER } from './constants/options';
import { DATA_PREFIX, QUERIES_PREFIX, PUBLIC_STATE_MAP } from './constants/state';
import * as types from './constants/actionTypes';
import { configurePolymer } from './utils/prepare';
import {
  storeToObserver,
  dispatchThunkAndExpect,
  pathToUid,
  selectPropByPath,
  itemUidToPath,
  queryResultsToPath,
  validatePath,
  toQueryParams,
  uidsToResponse,
  clone
} from './utils/helpers';
import ping from './plugins/ping';
import persistToken from './plugins/persistToken';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

// Setup Polymer configuration
configurePolymer();

const Simpla = new class Simpla {
  constructor() {
    const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
    this._store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunk)));
  }

  init(project) {
    this._store.dispatch(setOption('project', project));

    // Initialize endpoints
    this._store.dispatch(setOption('authEndpoint', AUTH_SERVER));
    this._store.dispatch(setOption('dataEndpoint', `${AUTH_SERVER}/projects/${project}/content`));
  }

  // Authentication
  login(...args) {
    return dispatchThunkAndExpect(this._store, login(...args), types.LOGIN_SUCCESSFUL);
  }

  logout(...args) {
    return dispatchThunkAndExpect(this._store, logout(...args), types.LOGOUT_SUCCESSFUL);
  }

  // Data
  find(options = {}) {
    let parentPath = options.parent,
        ancestorPath = options.ancestor;

    if (parentPath) {
      options.parent = pathToUid(parentPath);
    }

    if (ancestorPath) {
      options.ancestor = pathToUid(ancestorPath);
    }

    return Promise.resolve()
      .then(() => {
        if (parentPath) {
          validatePath(parentPath);
        }

        if (ancestorPath) {
          validatePath(ancestorPath);
        }
      })
      .then(() => dispatchThunkAndExpect(
        this._store,
        find(options),
        types.FIND_DATA_SUCCESSFUL
      ))
      .then(queryResultsToPath)
      .then(clone);
  }

  get(path, ...args) {
    const uid = pathToUid(path);
    return Promise.resolve()
      .then(() => validatePath(path))
      .then(() => dispatchThunkAndExpect(
        this._store,
        get(uid, ...args),
        types.GET_DATA_SUCCESSFUL
      ))
      .then(itemUidToPath)
      .then(clone);
  }

  set(path, ...args) {
    const uid = pathToUid(path);
    return Promise.resolve()
      .then(() => validatePath(path))
      .then(() => dispatchThunkAndExpect(
        this._store,
        set(uid, ...args),
        types.SET_DATA_SUCCESSFUL
      ))
      .then(itemUidToPath);
  }

  remove(path, ...args) {
    const uid = pathToUid(path);
    return Promise.resolve()
      .then(() => validatePath(path))
      .then(() => dispatchThunkAndExpect(
        this._store,
        remove(uid, ...args),
        types.REMOVE_DATA_SUCCESSFUL
      ))
      .then(itemUidToPath);
  }

  observe(path, ...args) {
    let callback = args.pop(),
        uid = pathToUid(path),
        pathInState,
        wrappedCallback;

    if (!uid) {
      throw new Error('Observe must be given a valid path');
    }

    validatePath(path);

    pathInState = [ DATA_PREFIX, 'content', uid ];
    wrappedCallback = () => this.get(path).then(callback);

    return storeToObserver(this._store).observe(pathInState, wrappedCallback);
  }

  observeQuery(query, callback) {
    let queryString,
        pathInStore,
        wrappedCallback;

    // Clone so as to not affect given param
    query = Object.assign({}, query);

    query.parent = pathToUid(query.parent);
    queryString = toQueryParams(query);
    pathInStore = [ QUERIES_PREFIX, queryString, 'matches' ];

    this._store.dispatch(observeQuery(query));

    wrappedCallback = (uids) => {
      return callback(
        queryResultsToPath(
          clone(uidsToResponse(uids, this._store.getState()))
        )
      );
    }

    return storeToObserver(this._store).observe(pathInStore, wrappedCallback);
  }

  prefetch(path) {
    return this.find({ ancestor: path }).then(() => {});
  }

  save(...args) {
    return dispatchThunkAndExpect(this._store, save(...args), types.SAVE_SUCCESSFUL);
  }

  // Editable
  editable(on) {
    this._store.dispatch(on ? editActive() : editInactive());
  }

  // State
  getState(substate) {
    let state = this._store.getState();

    if (substate) {
      let path = PUBLIC_STATE_MAP[substate];
      return path ? selectPropByPath(path, state) : undefined;
    }

    return Object.keys(PUBLIC_STATE_MAP).reduce((publicState, property) => {
      let path = PUBLIC_STATE_MAP[property];
      return Object.assign(
        publicState,
        { [ property ]: selectPropByPath(path, state) }
      );
    }, {});
  }

  observeState(substate, callback) {
    if (!substate) {
      throw new Error('No state given. Must include a state to observe e.g. Simpla.observeState(\'authenticated\', showAdmin)');
    }

    let realSubstate = PUBLIC_STATE_MAP[substate];
    return storeToObserver(this._store).observe(realSubstate, callback);
  }
}

// Init plugins
const plugins = [
  ping,
  persistToken
];

plugins.forEach(plugin => plugin(Simpla));

export default Simpla;
<|endoftext|>


<commit_before>'use strict';

var capitalize  = require( 'underscore.string/capitalize' )
,   clean       = require( 'underscore.string/clean' )
;

module.exports =
    {
        isIdentifier: function ( value )
        {
            return /^[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*$/.test( value.trim() );
        }

    ,   isNonBlank: function ( value )
        {
            return /\S/.test( value );
        }

    //  https://docs.npmjs.com/files/package.json#name
    //  https://github.com/npm/normalize-package-data/blob/v2.0.0/lib/fixer.js#L304
    //
    ,   isNpmName: function ( value )
        {
            return value === encodeURIComponent( value ) && value === value.toLowerCase();
        }

    ,   sentencify: function ( value )
        {
            return capitalize( clean( value )).replace( /([^!?.,:;])$/, '$1.' );
        }
    }
;
<commit_msg>fix(utils): ensure string methods apply to strings<commit_after>'use strict';

var capitalize  = require( 'underscore.string/capitalize' )
,   clean       = require( 'underscore.string/clean' )
;

module.exports =
    {
        isIdentifier: function ( value )
        {
            return /^[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*$/.test(( '' + value ).trim() );
        }

    ,   isNonBlank: function ( value )
        {
            return /\S/.test( value );
        }

    //  https://docs.npmjs.com/files/package.json#name
    //  https://github.com/npm/normalize-package-data/blob/v2.0.0/lib/fixer.js#L304
    //
    ,   isNpmName: function ( value )
        {
            return value === encodeURIComponent( value ) && value === ( '' + value ).toLowerCase();
        }

    ,   sentencify: function ( value )
        {
            return capitalize( clean( value )).replace( /([^!?.,:;])$/, '$1.' );
        }
    }
;
<|endoftext|>


<commit_before>const StringNumeralSystem = require('string-numeral-system')

const jsonpatch = require('fast-json-patch')
const msgpack = require('msgpack-lite')

const PACK_DIFF_KEYS = {
    value: 'v',
    op: 'o',
    path: 'p',
    v: 'value',
    o: 'op',
    p: 'path'
}
const UNPACK_DIFF_KEYS = {
    value: 'value',
    op: 'op',
    path: 'path',
    v: 'v',
    o: 'o',
    p: 'p'
}

function invertObject (obj) {
    return Object.keys(obj).reduce((output, key) => {
        const value = obj[key]

        output[value] = key

        return output
    }, {})
}

const OPERATIONS_KEYS = {
    add: 'a',
    remove: 'r',
    replace: 'p',
    move: 'm',
    copy: 'c',
    test: 't'
}
const INVERTED_OPERATIONS_KEYS = invertObject(OPERATIONS_KEYS);

function BinaryDiffProtocol (compressionMapping, throwOnUnmappedKey) {
    const decompressionMapping = invertObject(compressionMapping)

    function transformDiff (diff, keyMapping, operationsMapping, mapping) {
        const result = []

        for (const patch of diff) {
            const transformedDiff = {
                [keyMapping.path]: ''
            }

            const keys = patch[keyMapping.p].substring(1).split('/')

            for (const key of keys) {
                const mappedKey = mapping[key]

                if (!mappedKey && throwOnUnmappedKey) {
                    throw new Error(`Unmapped key: "${key}".`);
                }

                transformedDiff[keyMapping.path] += `/${mappedKey || key}`
            }

            transformedDiff[keyMapping.value] = patch[keyMapping.v]
            transformedDiff[keyMapping.op] = operationsMapping[patch[keyMapping.o]]

            result.push(transformedDiff)
        }

        return result
    }

    function compress (diff) {
        return transformDiff(diff, PACK_DIFF_KEYS, OPERATIONS_KEYS, compressionMapping)
    }

    function decompress (diff) {
        return transformDiff(diff, UNPACK_DIFF_KEYS, INVERTED_OPERATIONS_KEYS, decompressionMapping)
    }

    function pack (data, previousData) {
        const diff = jsonpatch.compare(previousData || {}, data)
        const compressedDiff = compress(diff)
        const encodedDiff = msgpack.encode(compressedDiff)

        return encodedDiff
    }

    function unpack (binaryData, previousData) {
        const encodedDiff = new Uint8Array(binaryData)
        const compressedDiff = msgpack.decode(encodedDiff)
        const diff = decompress(compressedDiff)
        const data = Object.assign({}, previousData)

        jsonpatch.apply(data, diff)

        return data
    }

    return {
        pack,
        unpack
    }
}

const CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='

/**
 * Generate a mapping for the compression of pack and unpacking. An existing mapping
 * can be provided to expand on, if it was generated using the same character set.
 *
 * @param {array} originalKeys - Keys to generate a mapping for.
 * @param {object} [existingMapping] - An existing mapping to expand on.
 * @param {string} chars - A custom character set to use for the generated keys.
 *
 * @returns {object} The generated mapping.
 */
function generateMapping (originalKeys, existingMapping, chars) {
    chars = chars || CHARS;

    const sns = StringNumeralSystem(chars)
    const mapping = Object.assign({}, existingMapping);

    let last = chars[0];

    if (existingMapping) {
        for (const existingKey of Object.keys(existingMapping)) {
            const value = existingMapping[existingKey];

            if (sns.max(value, last) === value) {
                last = sns.increment(value);
            }
        }
    }

    for (const originalKey of originalKeys) {
        if (!mapping[originalKey]) {
            mapping[originalKey] = last;

            last = sns.increment(last);
        }
    }

    return mapping;
}

module.exports = { create: BinaryDiffProtocol, generateMapping };
<commit_msg>Add function to inspect data<commit_after>const StringNumeralSystem = require('string-numeral-system')

const jsonpatch = require('fast-json-patch')
const msgpack = require('msgpack-lite')

const PACK_DIFF_KEYS = {
    value: 'v',
    op: 'o',
    path: 'p',
    v: 'value',
    o: 'op',
    p: 'path'
}
const UNPACK_DIFF_KEYS = {
    value: 'value',
    op: 'op',
    path: 'path',
    v: 'v',
    o: 'o',
    p: 'p'
}

function invertObject (obj) {
    return Object.keys(obj).reduce((output, key) => {
        const value = obj[key]

        output[value] = key

        return output
    }, {})
}

const OPERATIONS_KEYS = {
    add: 'a',
    remove: 'r',
    replace: 'p',
    move: 'm',
    copy: 'c',
    test: 't'
}
const INVERTED_OPERATIONS_KEYS = invertObject(OPERATIONS_KEYS);

function BinaryDiffProtocol (compressionMapping, throwOnUnmappedKey) {
    const decompressionMapping = invertObject(compressionMapping)

    function transformDiff (diff, keyMapping, operationsMapping, mapping) {
        const result = []

        for (const patch of diff) {
            const transformedDiff = {
                [keyMapping.path]: ''
            }

            const keys = patch[keyMapping.p].substring(1).split('/')

            for (const key of keys) {
                const mappedKey = mapping[key]

                if (!mappedKey && throwOnUnmappedKey) {
                    throw new Error(`Unmapped key: "${key}".`);
                }

                transformedDiff[keyMapping.path] += `/${mappedKey || key}`
            }

            transformedDiff[keyMapping.value] = patch[keyMapping.v]
            transformedDiff[keyMapping.op] = operationsMapping[patch[keyMapping.o]]

            result.push(transformedDiff)
        }

        return result
    }

    function compress (diff) {
        return transformDiff(diff, PACK_DIFF_KEYS, OPERATIONS_KEYS, compressionMapping)
    }

    function decompress (diff) {
        return transformDiff(diff, UNPACK_DIFF_KEYS, INVERTED_OPERATIONS_KEYS, decompressionMapping)
    }

    function pack (data, previousData, inspect) {
        const diff = jsonpatch.compare(previousData || {}, data)
        const compressedDiff = compress(diff)
        const encodedDiff = msgpack.encode(compressedDiff)

        if (typeof inspect === 'function') {
            inspect(data, diff, compressedDiff, encodedDiff);
        }

        return encodedDiff
    }

    function unpack (binaryData, previousData, inspect) {
        const encodedDiff = new Uint8Array(binaryData)
        const compressedDiff = msgpack.decode(encodedDiff)
        const diff = decompress(compressedDiff)
        const data = Object.assign({}, previousData)

        jsonpatch.apply(data, diff)

        if (typeof inspect === 'function') {
            inspect(data, diff, compressedDiff, encodedDiff);
        }

        return data
    }

    return {
        pack,
        unpack
    }
}

const CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='

/**
 * Generate a mapping for the compression of pack and unpacking. An existing mapping
 * can be provided to expand on, if it was generated using the same character set.
 *
 * @param {array} originalKeys - Keys to generate a mapping for.
 * @param {object} [existingMapping] - An existing mapping to expand on.
 * @param {string} chars - A custom character set to use for the generated keys.
 *
 * @returns {object} The generated mapping.
 */
function generateMapping (originalKeys, existingMapping, chars) {
    chars = chars || CHARS;

    const sns = StringNumeralSystem(chars)
    const mapping = Object.assign({}, existingMapping);

    let last = chars[0];

    if (existingMapping) {
        for (const existingKey of Object.keys(existingMapping)) {
            const value = existingMapping[existingKey];

            if (sns.max(value, last) === value) {
                last = sns.increment(value);
            }
        }
    }

    for (const originalKey of originalKeys) {
        if (!mapping[originalKey]) {
            mapping[originalKey] = last;

            last = sns.increment(last);
        }
    }

    return mapping;
}

module.exports = { create: BinaryDiffProtocol, generateMapping };
<|endoftext|>


<commit_before>/*
 * SimpleJS
 * https://github.com/TylerOBrien/SimpleJS
 *
 * Copyright (c) 2012 Tyler O'Brien
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * */

/*
 * AJAX fallback for IE6.
 * Might not work for IE5 and earlier.
 * */
if (typeof XMLHttpRequest === "undefined") {
	var XMLHttpRequest = function(){
		return new ActiveXObject("Microsoft.XMLHTTP");
	};
	XMLHttpRequest.prototype.isActiveX = true;
} else {
	XMLHttpRequest.prototype.isActiveX = false;
}

/*
 * send_s() returns Nothing
 * Input: Object
    * A "safe" version of XMLHttpRequest.send().
    * Is compatible with both ActiveX-based AJAX and otherwise.
    * */
XMLHttpRequest.prototype.send_s = function(args){
	if (typeof args === "undefined" || args === null) {
		if (this.isActiveX) {
			this.send();
		} else {
			this.send(null);
		}
	} else if ("method" in args && "queryString" in args && args.method === "post") {
		this.send(args.queryString);
	} else {
		this.send_s();
	}
};

/*
 * SimpleJS
 * */

var Simple = {};
(function(__Simple){
	"use strict";

	/*
	 * Internal AJAX operations performed here.
	 * */
	var AJAXInternal = {
		/*
		 * class Request
		 *
		 * */
		Request: function(args){
			this.async = __Simple.Exists(args["async"], true);
			this.charset = __Simple.Exists(args["charset"], "utf-8");
			this.contentType = __Simple.Exists(args["contentType"], "application/x-www-form-urlencoded");
			this.data = __Simple.Exists(args["data"], {});
			this.http = new XMLHttpRequest();
			this.method = __Simple.Exists(args["method"], "GET");
			this.onError = args["onError"];
			this.onConnect = args["onConnect"];
			this.onNotFound = args["onNotFound"];
			this.onProcess = args["onProcess"];
			this.onRequest = args["onRequest"];
			this.onSuccess = args["onSuccess"];
			this.queryString = __Simple.EncodeQueryString(this.data);
			this.timeBegin = 0;
			this.timeDifference = 0;
			this.timeEnd = 0;
			this.url = __Simple.Exists(args["url"], "/");
			this.urlToOpen = (this.method === "POST") ? this.url : (this.url + "?" + this.queryString);
		}
	};

	var ClassTypesInteral = {
		/* Populated by function at bottom using Simple.Each */
	};

	var CookieInternal = {
		data: {},

		/*
		 * Update() returns Nothing
		 * Input: Nothing
		     * Updates the cookie data.
	     * */
		Update: function(){
			this.data = {};
			var buffer = null;

			__Simple.Each(document.cookie.split(";"), function(){
				if (buffer = RegexInteral.cookie(this)) {
					CookieInternal.data[escape(buffer[1])] = escape(buffer[2]);
				}
			});
		}
	};

	/*
	 * Internal DOM operations performed here.
	 * */
	var DOMInternal = {
		busy: false,
		callbacks: [], /* Array of Function */
		ready: false,

		/*
		 * OnDOMContentLoaded() returns Nothing
		 * Input: Nothing
		     * Called by one of two possible event listeners.
			 * As function name suggests, is called when the DOM has finished loading.
		 * */
		OnDOMContentLoaded: function(){
			if (typeof document.addEventListener !== "undefined") {
				document.removeEventListener("DOMContentLoaded", DOMInternal.OnDOMContentLoaded, false);
				DOMInternal.OnReady();
			} else if (typeof document.attachEvent !== "undefined" && document.readyState === "complete" && document.body !== null) {
				document.detachEvent("onreadystatechange", DOMInternal.OnDOMContentLoaded);
				DOMInternal.OnReady();
			}
		},

		/*
		 * OnReady() returns Nothing
		 * Input: Nothing
		     * Called when the DOM is ready.
			 * Is usually called by DOMInternal.OnDOMContentLoaded.
		 * */
		OnReady: function(){
			if (this.busy === false && this.ready === false) {
				this.busy = true;
				Simple.Each(this.callbacks, function(){
					this.value();
				});
				this.ready = true;
				this.busy = false;
			}
		}
	};

	/*
	 * Internal Regular Expressions.
	 * */
	var RegexInternal = {
		cookie: /([^=]+)=(.*)/,
		queryString: /[?&]?([^&=]+)=?([^&]+)?/g
	};

	/*
	 * class Iterator
	 * Used for storing iteration informating by the Simple.Each function.
	 * Is only used internally, so there's no point in making it public-facing.
	 * */
	var Iterator = function(container){
		this.container = container;
		this.i = null;
		this.value = null;
	};

	/*
	 * AJAX() returns nothing
	 * Input: Object
	 * */
	__Simple.AJAX = function(args){
		var ajaxRequest = new AJAXInternal.Request(args);

		ajaxRequest.http.open(ajaxRequest.method, ajaxRequest.urlToOpen, ajaxRequest.async);
		ajaxRequest.http.setRequestHeader("Content-type", ajaxRequest.contentType+"; charset="+ajaxRequest.charset);
		ajaxRequest.http.onreadystatechange = function(){
			switch (ajaxRequest.http.readyState) {
				case 1: /* CONNECT */
					ajaxRequest.timeBegin = new Date().getTime();
					__Simple.Call(ajaxRequest.onConnect);
				break;
				case 2: /* REQUEST RECEIVED */
					__Simple.Call(ajaxRequest.onRequest);
				break;
				case 3: /* PROCESSING */
					__Simple.Call(ajaxRequest.onProcess);
				break;
				case 4: /* COMPLETE */
					if (typeof ajaxRequest.timeout !== "undefined") {
						clearTimeout(ajaxRequest.timeout);
					}

					ajaxRequest.timeEnd = new Date().getTime();
					ajaxRequest.timeDifference = (ajaxRequest.timeEnd - ajaxRequest.timeBegin);

					switch (ajaxRequest.http.status) {
						case 200: __Simple.Call(ajaxRequest.onSuccess, ajaxRequest.http.responseText, ajaxRequest.timeDifference);
						break;
						case 404: __Simple.Call(ajaxRequest.onNotFound, ajaxRequest.http.responseText, ajaxRequest.timeDifference);
						default:  __Simple.Call(ajaxRequest.onError, [ajaxRequest.http.responseText,ajaxRequest.http.status], ajaxRequest.timeDifference);
						break;
					}
				break;
			}
		};

		/*
		 * Add a new timeout if one is given.
		 * The time is assumed to be milliseconds.
		 * */
		if (typeof args["timeout"] === "number") {
			ajaxRequest.timeout = setTimeout(function(){
				ajaxRequest.http.abort();
				__Simple.Call(ajaxRequest.onTimeout);
			}, args["timeout"]);
		}

		ajaxRequest.http.send_s(ajaxRequest);
	};

	/*
	 * Call() returns Mixed
	 * Input: Mixed, Mixed, Mixed
	 * */
	__Simple.Call = function(callback, first, second){
		if (__Simple.Type(callback) === "function") {
			if (typeof second !== "undefined") return callback(first, second);
			else if (typeof first !== "undefined") return callback(first);
			else return callback();
		}
	};

	__Simple.Cookie = {
		/*
		 * Get() returns String
		 * Input: String
		 * */
		Get: function(name){
			return CookieInternal.data[name];
		},

		Set: function(name, value, expires){

		},
	};

	/*
	 * DOMElement() returns Mixed
	 *	Input: String, String
	 * */
	__Simple.DOMElement = function(elementString, context){
		if (typeof context === "undefined") {
			context = document;
		}

		switch (elementString[0]) {
			case "#": return context.getElementById(elementString.substring(1));
			case ".": return context.getElementsByClassName(elementString.substring(1));
			case ":": return context.getElementsByName(elementString.substring(1));
			default:  return context.getElementsByTagName(elementString);
		}
	};

	/*
	 * DOMReady() returns nothing
	 * Input: Function
	     * Calls the passed function when the DOM is ready.
	 * */
	__Simple.DOMReady = function(callback){
		if (__Simple.Type(callback) === "function") {
			if (DOMInteral.ready === false && DOMInteral.busy === false) {
				DOMInteral.callbacks.push(callback);
			} else {
				callback();
			}
		}
	};

	/*
	 * DecodeQueryString() returns Object
	 * Input: String
	     * Converts a passed query string in this format:
		     * id=42&name=John+Doe&type=user
	     * Into an object containing the defined variables.
		 * All instances of "+" will be converted to spaces.
		 *
		 * Any variables not given a value, like so:
		     * foo&bar&baz
	     * Will be NULL valued in the object.
	 * */
	__Simple.DecodeQueryString = function(queryString){
		queryString = queryString.replace("+", " ");

		var buffer = RegexInternal.queryString.exec(queryString);
		var result = {};

		while (buffer !== null) {
			result[decodeURIComponent(buffer[1])] = (typeof buffer[2] !== "undefined" ? decodeURIComponent(buffer[2]) : null);
			buffer = RegexInternal.queryString.exec(queryString);
		}

		return result;
	};

	/*
	 * Simple.Each() returns nothing
	 * Input: Mixed, Function
	 * */
	__Simple.Each = function(haystack, callback){
		if (typeof haystack !== "undefined") {
			/* Possible haystack shortcuts */
			if (haystack === __Simple.Cookie) haystack = CookieInternal.data;
			else if (haystack === __Simple.GET) haystack = __GET;

			/* Iterator will hold a reference to haystack */
			var iterator = new Iterator(haystack);

			/* Presumably only an Array will have a "length" property */
			if (haystack.hasOwnProperty("length")) {
				iterator.i = 0;
				var end = haystack.length;
				for (; iterator.i < end; iterator.i++) {
					iterator.value = haystack[iterator.i];
					if (callback.call(iterator.value, iterator) === false) {
						break;
					}
				}
			} else {
				for (iterator.i in haystack) {
					iterator.value = haystack[iterator.i];
					if (callback.call(iterator.value, iterator) === false) {
						break;
					}
				}
			}
		}
	};

	/*
	 * Exists() returns Mixed
	 * Input: Mixed, Mixed, Boolean
	 * */
	__Simple.Exists = function(object, override, doReturnBoolean){
		var useBool = (typeof doReturnBoolean !== "undefined" && doReturnBoolean);

		if (typeof object !== "undefined") {
			if (useBool) return true;
			else return object;
		} else {
			if (useBool) return false;
			else return override;
		}
	};

	/*
	 * EncodeQueryString() returns String
	 * Input: Object
	 * */
	__Simple.EncodeQueryString = function(object){
		var result = "";

		for (var index in object) {
			result += (index + "=" + object[index] + "&");
		}

		/* Trim off the extra ampersand. */
		if (result.length > 0) {
			result = result.substring(0, result.length-1);
		}

		return result.replace(" ", "+");
	};

	/*
	 * GET
	 * Contains functions for accessing GET variables.
	 * */
	__Simple.GET = {
		/*
		 * Exists() returns Boolean
		 * Input: String
		     * Returns true if the passed GET variable has been defined.
			 * Does not require a value to have been assigned.
		 * */
		Exists: function(name){
			return typeof __GET[name] !== "undefined";
		},

		/*
		 * Exists() returns String|undefined
		 * Input: String
		     * Returns the value of the passed GET variable.
			 * If the GET variable has no value assigned this will return NULL.
			 * If the GET variable does not exist this will return undefined.
		 * */
		Find: function(name){
			return __Simple.GET.Exists(name) ? __GET[name] : undefined;
		}
	};

	/*
	 * IsArray() returns Boolean
	 * Input: Mixed
	 * */
	__Simple.IsArray = function(object){
		return __Simple.Type(object) === "array";
	};

	/*
	 * IsEmptyObject() returns Boolean
	 * Input: Mixed
	 * */
	__Simple.IsEmptyObject = function(object){
		for (var index in object) {
			return false;
		}
		return true;
	};

	/*
	 * IsFunction() returns Boolean
	 * Input: Mixed
	 * */
	__Simple.IsFunction = function(object){
		return __Simple.Type(object) === "function";
	};

	/*
	 * IsNumeric() returns Boolean
	 * Input: Mixed
	 * */
	__Simple.IsNumeric = function(object){
		return !isNaN(parseFloat(object)) && isFinite(object);
	};

	/*
	 * Simple.Type() returns String
	 * Input: Mixed
	     * Returns the type of the passed object.
	     * Borrowed from jQuery.
	 * */
	__Simple.Type = function(object){
		return object === null ? "null" : (ClassTypesInteral[Object.prototype.toString.call(object)] || "object");
	};

	/*
	 * Populate the class types.
	 * Borrowed from jQuery.
	 * */
	__Simple.Each("Array Boolean Date Function Number Object RegExp String".split(" "), function(itr){
		ClassTypesInteral["[object " + itr.value + "]"] = itr.value.toLowerCase();
	});

	/* Decode the browser's query string, if it exists. */
	var __GET = __Simple.DecodeQueryString(document.location.search);

	/*
	 * Different/older browsers may have different methods for DOM loading.
	 * Based on jQuery.
	 * */
	if (typeof document.addEventListener !== "undefined") {
		document.addEventListener("DOMContentLoaded", DOMInternal.OnDOMContentLoaded, false);
		window.addEventListener("load", DOMInternal.OnReady, false);
	} else if (typeof document.attachEvent !== "undefined") {
		document.attachEvent("onreadystatechange", DOMInternal.OnDOMContentLoaded);
		window.attachEvent("onload", DOMInternal.OnReady, false);
	} else {
		window.onload = DOMInternal.OnReady;
	}
}(Simple));<commit_msg>Updated Readme.<commit_after>/*
 * SimpleJS
 * https://github.com/TylerOBrien/SimpleJS
 *
 * Copyright (c) 2012 Tyler O'Brien
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * */

/*
 * AJAX fallback for IE6.
 * Might not work for IE5 and earlier.
 * */
if (typeof XMLHttpRequest === "undefined") {
	var XMLHttpRequest = function(){
		return new ActiveXObject("Microsoft.XMLHTTP");
	};
	XMLHttpRequest.prototype.isActiveX = true;
} else {
	XMLHttpRequest.prototype.isActiveX = false;
}

/*
 * send_s() returns Nothing
 * Input: Object
    * A "safe" version of XMLHttpRequest.send().
    * Is compatible with both ActiveX-based AJAX and otherwise.
    * */
XMLHttpRequest.prototype.send_s = function(args){
	if (typeof args === "undefined" || args === null) {
		if (this.isActiveX) {
			this.send();
		} else {
			this.send(null);
		}
	} else if ("method" in args && "queryString" in args && args.method === "post") {
		this.send(args.queryString);
	} else {
		this.send_s();
	}
};

/*
 * SimpleJS
 * */

var Simple = {};
(function(__Simple){
	"use strict";

	/*
	 * Internal AJAX operations performed here.
	 * */
	var AJAXInternal = {
		/*
		 * class Request
		 *
		 * */
		Request: function(args){
			this.async = __Simple.Exists(args["async"], true);
			this.charset = __Simple.Exists(args["charset"], "utf-8");
			this.contentType = __Simple.Exists(args["contentType"], "application/x-www-form-urlencoded");
			this.data = __Simple.Exists(args["data"], {});
			this.http = new XMLHttpRequest();
			this.method = __Simple.Exists(args["method"], "GET");
			this.onError = args["onError"];
			this.onConnect = args["onConnect"];
			this.onNotFound = args["onNotFound"];
			this.onProcess = args["onProcess"];
			this.onRequest = args["onRequest"];
			this.onSuccess = args["onSuccess"];
			this.queryString = __Simple.EncodeQueryString(this.data);
			this.timeBegin = 0;
			this.timeDifference = 0;
			this.timeEnd = 0;
			this.url = __Simple.Exists(args["url"], "/");
			this.urlToOpen = (this.method === "POST") ? this.url : (this.url + "?" + this.queryString);
		}
	};

	var ClassTypesInteral = {
		/* Populated by function at bottom using Simple.Each */
	};

	var CookieInternal = {
		data: {},

		/*
		 * Update() returns Nothing
		 * Input: Nothing
		     * Updates the cookie data.
	     * */
		Update: function(){
			this.data = {};
			var buffer = null;

			__Simple.Each(document.cookie.split(";"), function(){
				if (buffer = RegexInteral.cookie(this)) {
					CookieInternal.data[escape(buffer[1])] = escape(buffer[2]);
				}
			});
		}
	};

	/*
	 * Internal DOM operations performed here.
	 * */
	var DOMInternal = {
		busy: false,
		callbacks: [], /* Array of Function */
		ready: false,

		/*
		 * OnDOMContentLoaded() returns Nothing
		 * Input: Nothing
		     * Called by one of two possible event listeners.
			 * As function name suggests, is called when the DOM has finished loading.
		 * */
		OnDOMContentLoaded: function(){
			if (typeof document.addEventListener !== "undefined") {
				document.removeEventListener("DOMContentLoaded", DOMInternal.OnDOMContentLoaded, false);
				DOMInternal.OnReady();
			} else if (typeof document.attachEvent !== "undefined" && document.readyState === "complete" && document.body !== null) {
				document.detachEvent("onreadystatechange", DOMInternal.OnDOMContentLoaded);
				DOMInternal.OnReady();
			}
		},

		/*
		 * OnReady() returns Nothing
		 * Input: Nothing
		     * Called when the DOM is ready.
			 * Is usually called by DOMInternal.OnDOMContentLoaded.
		 * */
		OnReady: function(){
			if (this.busy === false && this.ready === false) {
				this.busy = true;
				Simple.Each(this.callbacks, function(){
					this.value();
				});
				this.ready = true;
				this.busy = false;
			}
		}
	};

	/*
	 * Internal Regular Expressions.
	 * */
	var RegexInternal = {
		cookie: /([^=]+)=(.*)/,
		queryString: /[?&]?([^&=]+)=?([^&]+)?/g
	};

	/*
	 * class Iterator
	 * Used for storing iteration informating by the Simple.Each function.
	 * Is only used internally, so there's no point in making it public-facing.
	 * */
	var Iterator = function(container){
		this.container = container;
		this.i = null;
		this.value = null;
	};

	/*
	 * AJAX() returns nothing
	 * Input: Object
	 * */
	__Simple.AJAX = function(args){
		var ajaxRequest = new AJAXInternal.Request(args);

		ajaxRequest.http.open(ajaxRequest.method, ajaxRequest.urlToOpen, ajaxRequest.async);
		ajaxRequest.http.setRequestHeader("Content-type", ajaxRequest.contentType+"; charset="+ajaxRequest.charset);
		ajaxRequest.http.onreadystatechange = function(){
			switch (ajaxRequest.http.readyState) {
				case 1: /* CONNECT */
					ajaxRequest.timeBegin = new Date().getTime();
					__Simple.Call(ajaxRequest.onConnect);
				break;
				case 2: /* REQUEST RECEIVED */
					__Simple.Call(ajaxRequest.onRequest);
				break;
				case 3: /* PROCESSING */
					__Simple.Call(ajaxRequest.onProcess);
				break;
				case 4: /* COMPLETE */
					if (typeof ajaxRequest.timeout !== "undefined") {
						clearTimeout(ajaxRequest.timeout);
					}

					ajaxRequest.timeEnd = new Date().getTime();
					ajaxRequest.timeDifference = (ajaxRequest.timeEnd - ajaxRequest.timeBegin);

					switch (ajaxRequest.http.status) {
						case 200: __Simple.Call(ajaxRequest.onSuccess, ajaxRequest.http.responseText, ajaxRequest.timeDifference);
						break;
						case 404: __Simple.Call(ajaxRequest.onNotFound, ajaxRequest.http.responseText, ajaxRequest.timeDifference);
						default:  __Simple.Call(ajaxRequest.onError, [ajaxRequest.http.responseText,ajaxRequest.http.status], ajaxRequest.timeDifference);
						break;
					}
				break;
			}
		};

		/*
		 * Add a new timeout if one is given.
		 * The time is assumed to be milliseconds.
		 * */
		if (typeof args["timeout"] === "number") {
			ajaxRequest.timeout = setTimeout(function(){
				ajaxRequest.http.abort();
				__Simple.Call(ajaxRequest.onTimeout);
			}, args["timeout"]);
		}

		ajaxRequest.http.send_s(ajaxRequest);
	};

	/*
	 * Call() returns Mixed
	 * Input: Mixed, Mixed, Mixed
	 * */
	__Simple.Call = function(callback, first, second){
		if (__Simple.Type(callback) === "function") {
			if (typeof second !== "undefined") return callback(first, second);
			else if (typeof first !== "undefined") return callback(first);
			else return callback();
		}
	};

	__Simple.Cookie = {
		/*
		 * Get() returns String
		 * Input: String
		 * */
		Get: function(name){
			return CookieInternal.data[name];
		},

		Set: function(name, value, expires){

		},
	};

	/*
	 * DOMElement() returns Mixed
	 *	Input: String, String
	 * */
	__Simple.DOMElement = function(elementString, context){
		if (typeof context === "undefined") {
			context = document;
		}

		switch (elementString[0]) {
			case "#": return context.getElementById(elementString.substring(1));
			case ".": return context.getElementsByClassName(elementString.substring(1));
			case ":": return context.getElementsByName(elementString.substring(1));
			default:  return context.getElementsByTagName(elementString);
		}
	};

	/*
	 * DOMReady() returns nothing
	 * Input: Function
	     * Calls the passed function when the DOM is ready.
	 * */
	__Simple.DOMReady = function(callback){
		if (__Simple.Type(callback) === "function") {
			if (DOMInteral.ready === false && DOMInteral.busy === false) {
				DOMInteral.callbacks.push(callback);
			} else {
				callback();
			}
		}
	};

	/*
	 * DecodeQueryString() returns Object
	 * Input: String
	     * Converts a passed query string in this format:
		     * id=42&name=John+Doe&type=user
	     * Into an object containing the defined variables.
		 * All instances of "+" will be converted to spaces.
		 *
		 * Any variables not given a value, like so:
		     * foo&bar&baz
	     * Will be NULL valued in the object.
	 * */
	__Simple.DecodeQueryString = function(queryString){
		queryString = queryString.replace("+", " ");

		var buffer = RegexInternal.queryString.exec(queryString);
		var result = {};

		while (buffer !== null) {
			result[decodeURIComponent(buffer[1])] = (typeof buffer[2] !== "undefined" ? decodeURIComponent(buffer[2]) : null);
			buffer = RegexInternal.queryString.exec(queryString);
		}

		return result;
	};

	/*
	 * Simple.Each() returns nothing
	 * Input: Mixed, Function
	 * */
	__Simple.Each = function(haystack, callback){
		if (typeof haystack !== "undefined") {
			/* Possible haystack shortcuts */
			if (haystack === __Simple.Cookie) haystack = CookieInternal.data;
			else if (haystack === __Simple.GET) haystack = __GET;

			/* Iterator will hold a reference to haystack */
			var iterator = new Iterator(haystack);

			/* Presumably only an Array will have a "length" property */
			if (haystack.hasOwnProperty("length")) {
				iterator.i = 0;
				var end = haystack.length;
				for (; iterator.i < end; iterator.i++) {
					iterator.value = haystack[iterator.i];
					if (callback.call(iterator.value, iterator) === false) {
						break;
					}
				}
			} else {
				for (iterator.i in haystack) {
					iterator.value = haystack[iterator.i];
					if (callback.call(iterator.value, iterator) === false) {
						break;
					}
				}
			}
		}
	};

	/*
	 * Exists() returns Mixed
	 * Input: Mixed, Mixed, Boolean
	     * Used for determining if "object" is defined.
		 * If defined "object" will be returned, otherwise "override" is returned.
		 * If "doReturnBoolean" is true then false/true is returned in place of object/override.
	 * */
	__Simple.Exists = function(object, override, doReturnBoolean){
		var useBool = (typeof doReturnBoolean !== "undefined" && doReturnBoolean);

		if (typeof object !== "undefined") {
			if (useBool) return true;
			else return object;
		} else {
			if (useBool) return false;
			else return override;
		}
	};

	/*
	 * EncodeQueryString() returns String
	 * Input: Object
	     * Encodes a passed Object into a query string.
		 * For example, this:
		     * {name:"John Doe", id:42}
	     * Would become:
		     * name=John+Doe&id=42
	 * */
	__Simple.EncodeQueryString = function(object){
		var result = "";
		for (var index in object) {
			result += (index + "=" + object[index] + "&");
		}

		if (result.length > 0) { /* Trim off the extra ampersand. */
			result = result.substring(0, result.length-1);
		}
		return result.replace(" ", "+");
	};

	/*
	 * GET
	 * Contains functions for accessing GET variables.
	 * */
	__Simple.GET = {
		/*
		 * Exists() returns Boolean
		 * Input: String
		     * Returns true if the passed GET variable has been defined.
			 * Does not require a value to have been assigned.
		 * */
		Exists: function(name){
			return typeof __GET[name] !== "undefined";
		},

		/*
		 * Exists() returns String|undefined
		 * Input: String
		     * Returns the value of the passed GET variable.
			 * If the GET variable has no value assigned this will return NULL.
			 * If the GET variable does not exist this will return undefined.
		 * */
		Find: function(name){
			return __Simple.GET.Exists(name) ? __GET[name] : undefined;
		}
	};

	/*
	 * IsArray() returns Boolean
	 * Input: Mixed
	 * */
	__Simple.IsArray = function(object){
		return __Simple.Type(object) === "array";
	};

	/*
	 * IsEmptyObject() returns Boolean
	 * Input: Mixed
	 * */
	__Simple.IsEmptyObject = function(object){
		for (var index in object) {
			return false;
		}
		return true;
	};

	/*
	 * IsFunction() returns Boolean
	 * Input: Mixed
	 * */
	__Simple.IsFunction = function(object){
		return __Simple.Type(object) === "function";
	};

	/*
	 * IsNumeric() returns Boolean
	 * Input: Mixed
	 * */
	__Simple.IsNumeric = function(object){
		return !isNaN(parseFloat(object)) && isFinite(object);
	};

	/*
	 * Simple.Type() returns String
	 * Input: Mixed
	     * Returns the type of the passed object.
	     * Borrowed from jQuery.
	 * */
	__Simple.Type = function(object){
		return object === null ? "null" : (ClassTypesInteral[Object.prototype.toString.call(object)] || "object");
	};

	/*
	 * Populate the class types.
	 * Borrowed from jQuery.
	 * */
	__Simple.Each("Array Boolean Date Function Number Object RegExp String".split(" "), function(itr){
		ClassTypesInteral["[object " + itr.value + "]"] = itr.value.toLowerCase();
	});

	/* Decode the browser's query string, if it exists. */
	var __GET = __Simple.DecodeQueryString(document.location.search);

	/*
	 * Different/older browsers may have different methods for DOM loading.
	 * Based on jQuery.
	 * */
	if (typeof document.addEventListener !== "undefined") {
		document.addEventListener("DOMContentLoaded", DOMInternal.OnDOMContentLoaded, false);
		window.addEventListener("load", DOMInternal.OnReady, false);
	} else if (typeof document.attachEvent !== "undefined") {
		document.attachEvent("onreadystatechange", DOMInternal.OnDOMContentLoaded);
		window.attachEvent("onload", DOMInternal.OnReady, false);
	} else {
		window.onload = DOMInternal.OnReady;
	}
}(Simple));<|endoftext|>


<commit_before>var text = [];
var delay = 50;
var currentWord = 0;
var currentChar = 0;
var dest = null;

function type() {
    dest.innerHTML = text[currentWord].substr(0, ++currentChar);
    if (currentChar > text[currentWord].length) setTimeout("unType()", 1500);
    else                                        setTimeout("type()", delay);
}

function unType() {
    dest.innerHTML = text[currentWord].substr(0, currentChar);
    if (--currentChar === 0) {
        dest.innerHTML = "
"; // otherwise page will jump due to line deletion
        if (currentWord + 1 === text.length) currentWord = 0;
        else ++currentWord;
        setTimeout("type()", 750);
    } else {
        setTimeout("unType()", delay/2);
    }
}

function startTyping(textParam, delayParam, destinationParam) {
    text = textParam;
    delay = delayParam;
    dest = document.getElementById(destinationParam);
    setTimeout("type()", 500);
}

// start 3s after page load
//window.onload = setTimeout(startTyping(["Software Developer", "University of Texas Student", "Entrepreneur"], 50, "messages"),
                            //30000);

window.addEventListener("load", function () {
    setTimeout(startTyping(["Software Developer", "University of Texas Student", "Entrepreneur"], 50, "messages"),
        7000);
}, false);<commit_msg>changed delay to 10s<commit_after>var text = [];
var delay = 50;
var currentWord = 0;
var currentChar = 0;
var dest = null;

function type() {
    dest.innerHTML = text[currentWord].substr(0, ++currentChar);
    if (currentChar > text[currentWord].length) setTimeout("unType()", 1500);
    else                                        setTimeout("type()", delay);
}

function unType() {
    dest.innerHTML = text[currentWord].substr(0, currentChar);
    if (--currentChar === 0) {
        dest.innerHTML = "
"; // otherwise page will jump due to line deletion
        if (currentWord + 1 === text.length) currentWord = 0;
        else ++currentWord;
        setTimeout("type()", 750);
    } else {
        setTimeout("unType()", delay/2);
    }
}

function startTyping(textParam, delayParam, destinationParam) {
    text = textParam;
    delay = delayParam;
    dest = document.getElementById(destinationParam);
    setTimeout("type()", 500);
}

// start 10s after page load
window.addEventListener("load", function () {
    setTimeout(startTyping(["Software Developer", "University of Texas Student", "Entrepreneur"], 50, "messages"),
        10000);
}, false);<|endoftext|>


<commit_before>import './Config'
import './Controller'
import './ErrorHandler'
import './Grind'
import './HttpServer'
import './Log'
import './Paths'
import './UrlGenerator'

import './Errors'
import './Errors/MissingPackageError'
import './Errors/RoutesLoadError'

import './Routing/Router'
import './Routing/ResourceRouteBuilder'

export default Grind

export {
	Config,
	Controller,
	ErrorHandler,
	Errors,
	Grind,
	HttpServer,
	MissingPackageError,
	Paths,
	ResourceRouteBuilder,
	Router,
	RoutesLoadError,
	UrlGenerator
}

global.Log = Log
<commit_msg>Fixed a bug in index.js that would override Log This should never happen, but it is if multiple versions of grind get included via packages<commit_after>import './Config'
import './Controller'
import './ErrorHandler'
import './Grind'
import './HttpServer'
import './Log'
import './Paths'
import './UrlGenerator'

import './Errors'
import './Errors/MissingPackageError'
import './Errors/RoutesLoadError'

import './Routing/Router'
import './Routing/ResourceRouteBuilder'

export default Grind

export {
	Config,
	Controller,
	ErrorHandler,
	Errors,
	Grind,
	HttpServer,
	MissingPackageError,
	Paths,
	ResourceRouteBuilder,
	Router,
	RoutesLoadError,
	UrlGenerator
}

if(global.Log.isNil) {
	global.Log = Log
}
<|endoftext|>


<commit_before>/* @flow */

import { install } from './install'
import { createMatcher } from './create-matcher'
import { HashHistory, getHash } from './history/hash'
import { HTML5History, getLocation } from './history/html5'
import { AbstractHistory } from './history/abstract'
import { inBrowser, supportsHistory } from './util/dom'
import { assert } from './util/warn'
import { cleanPath } from './util/path'
import { normalizeLocation } from './util/location'

export default class VueRouter {
  static install: () => void;

  app: any;
  options: RouterOptions;
  mode: string;
  history: HashHistory | HTML5History | AbstractHistory;
  match: Matcher;
  fallback: boolean;
  beforeHooks: Array<?NavigationGuard>;
  afterHooks: Array<?((to: Route, from: Route) => any)>;

  constructor (options: RouterOptions = {}) {
    this.app = null
    this.options = options
    this.beforeHooks = []
    this.afterHooks = []
    this.match = createMatcher(options.routes || [])

    let mode = options.mode || 'hash'
    this.fallback = mode === 'history' && !supportsHistory
    if (this.fallback) {
      mode = 'hash'
    }
    if (!inBrowser) {
      mode = 'abstract'
    }
    this.mode = mode

    switch (mode) {
      case 'history':
        this.history = new HTML5History(this, options.base)
        break
      case 'hash':
        this.history = new HashHistory(this, options.base, this.fallback)
        break
      case 'abstract':
        this.history = new AbstractHistory(this)
        break
      default:
        process.env.NODE_ENV !== 'production' && assert(false, `invalid mode: ${mode}`)
    }
  }

  get currentRoute (): ?Route {
    return this.history && this.history.current
  }

  init (app: any /* Vue component instance */) {
    process.env.NODE_ENV !== 'production' && assert(
      install.installed,
      `not installed. Make sure to call \`Vue.use(VueRouter)\` ` +
      `before creating root instance.`
    )

    this.app = app

    const history = this.history

    if (history instanceof HTML5History) {
      history.transitionTo(getLocation(history.base))
    } else if (history instanceof HashHistory) {
      const setupHashListener = () => {
        window.addEventListener('hashchange', () => {
          history.onHashChange()
        })
      }
      history.transitionTo(getHash(), setupHashListener, setupHashListener)
    }

    history.listen(route => {
      this.app._route = route
    })
  }

  beforeEach (fn: Function) {
    this.beforeHooks.push(fn)
  }

  afterEach (fn: Function) {
    this.afterHooks.push(fn)
  }

  push (location: RawLocation) {
    this.history.push(location)
  }

  replace (location: RawLocation) {
    this.history.replace(location)
  }

  go (n: number) {
    this.history.go(n)
  }

  back () {
    this.go(-1)
  }

  forward () {
    this.go(1)
  }

  getMatchedComponents (to?: RawLocation): Array<any> {
    const route = to
      ? this.resolve(to).resolved
      : this.currentRoute
    if (!route) {
      return []
    }
    return [].concat.apply([], route.matched.map(m => {
      return Object.keys(m.components).map(key => {
        return m.components[key]
      })
    }))
  }

  resolve (
    to: RawLocation,
    current?: Route,
    append?: boolean
  ): {
    normalizedTo: Location,
    resolved: Route,
    href: string
  } {
    const normalizedTo = normalizeLocation(to, current || this.history.current, append)
    const resolved = this.match(normalizedTo, current)
    const fullPath = resolved.redirectedFrom || resolved.fullPath
    const base = this.history.base
    const href = createHref(base, fullPath, this.mode)
    return {
      normalizedTo,
      resolved,
      href
    }
  }
}

function createHref (base: string, fullPath: string, mode) {
  var path = mode === 'hash' ? '/#' + fullPath : fullPath
  return base ? cleanPath(base + path) : path
}

VueRouter.install = install

if (inBrowser && window.Vue) {
  window.Vue.use(VueRouter)
}
<commit_msg>fix router-link href for hash mode with no base (fix #969)<commit_after>/* @flow */

import { install } from './install'
import { createMatcher } from './create-matcher'
import { HashHistory, getHash } from './history/hash'
import { HTML5History, getLocation } from './history/html5'
import { AbstractHistory } from './history/abstract'
import { inBrowser, supportsHistory } from './util/dom'
import { assert } from './util/warn'
import { cleanPath } from './util/path'
import { normalizeLocation } from './util/location'

export default class VueRouter {
  static install: () => void;

  app: any;
  options: RouterOptions;
  mode: string;
  history: HashHistory | HTML5History | AbstractHistory;
  match: Matcher;
  fallback: boolean;
  beforeHooks: Array<?NavigationGuard>;
  afterHooks: Array<?((to: Route, from: Route) => any)>;

  constructor (options: RouterOptions = {}) {
    this.app = null
    this.options = options
    this.beforeHooks = []
    this.afterHooks = []
    this.match = createMatcher(options.routes || [])

    let mode = options.mode || 'hash'
    this.fallback = mode === 'history' && !supportsHistory
    if (this.fallback) {
      mode = 'hash'
    }
    if (!inBrowser) {
      mode = 'abstract'
    }
    this.mode = mode

    switch (mode) {
      case 'history':
        this.history = new HTML5History(this, options.base)
        break
      case 'hash':
        this.history = new HashHistory(this, options.base, this.fallback)
        break
      case 'abstract':
        this.history = new AbstractHistory(this)
        break
      default:
        process.env.NODE_ENV !== 'production' && assert(false, `invalid mode: ${mode}`)
    }
  }

  get currentRoute (): ?Route {
    return this.history && this.history.current
  }

  init (app: any /* Vue component instance */) {
    process.env.NODE_ENV !== 'production' && assert(
      install.installed,
      `not installed. Make sure to call \`Vue.use(VueRouter)\` ` +
      `before creating root instance.`
    )

    this.app = app

    const history = this.history

    if (history instanceof HTML5History) {
      history.transitionTo(getLocation(history.base))
    } else if (history instanceof HashHistory) {
      const setupHashListener = () => {
        window.addEventListener('hashchange', () => {
          history.onHashChange()
        })
      }
      history.transitionTo(getHash(), setupHashListener, setupHashListener)
    }

    history.listen(route => {
      this.app._route = route
    })
  }

  beforeEach (fn: Function) {
    this.beforeHooks.push(fn)
  }

  afterEach (fn: Function) {
    this.afterHooks.push(fn)
  }

  push (location: RawLocation) {
    this.history.push(location)
  }

  replace (location: RawLocation) {
    this.history.replace(location)
  }

  go (n: number) {
    this.history.go(n)
  }

  back () {
    this.go(-1)
  }

  forward () {
    this.go(1)
  }

  getMatchedComponents (to?: RawLocation): Array<any> {
    const route = to
      ? this.resolve(to).resolved
      : this.currentRoute
    if (!route) {
      return []
    }
    return [].concat.apply([], route.matched.map(m => {
      return Object.keys(m.components).map(key => {
        return m.components[key]
      })
    }))
  }

  resolve (
    to: RawLocation,
    current?: Route,
    append?: boolean
  ): {
    normalizedTo: Location,
    resolved: Route,
    href: string
  } {
    const normalizedTo = normalizeLocation(to, current || this.history.current, append)
    const resolved = this.match(normalizedTo, current)
    const fullPath = resolved.redirectedFrom || resolved.fullPath
    const base = this.history.base
    const href = createHref(base, fullPath, this.mode)
    return {
      normalizedTo,
      resolved,
      href
    }
  }
}

function createHref (base: string, fullPath: string, mode) {
  var path = mode === 'hash' ? '#' + fullPath : fullPath
  return base ? cleanPath(base + '/' + path) : path
}

VueRouter.install = install

if (inBrowser && window.Vue) {
  window.Vue.use(VueRouter)
}
<|endoftext|>


<commit_before>"use strict";

const FileTree = require('../web/public/javascript/shared/filetree');
const FileNode = require('../web/public/javascript/shared/filenode');
const FileWatcher = require('./FileWatcher');
const fs = require('fs-promise');
const path = require('path');

class FileManager extends FileTree
{
  constructor(project)
  {
    super();
    this.root = new ServerFolderNode(this, undefined, project.name);
    this.project = project;
    this.parentPath = "projects/";

    this.root.make();

    this.fileWatcher = new FileWatcher(this);
  }

  sendFolder(session, folder)
  {
    for(let childFolder of folder.children)
    {
      session.send({
        type: "filetree",
        action: "add",
        isFile: childFolder.isFile,
        path: childFolder.clientPath
      });

      if(!childFolder.isFile)
        this.sendFolder(session, childFolder);
    }
  }

  async createNode(parentPath, name, isFile)
  {
    let parentFolder = this.getFolder(parentPath);
    name = this.cleanName(name);
    let nameErrors = this.validateName(name);

    if(!parentFolder)
      throw "Parent folder is undefined.";
    if(parentFolder.containsChild(name))
      throw `${parentPath}/${name} already exists.`;
    if(nameErrors)
      throw nameErrors;

    let node = isFile ? parentFolder.registerFile(name) :
                        parentFolder.registerSubFolder(name);

    await node.make().catch((err) => {
      node.destroy();
      throw err.message;
    });

    this.project.broadcast({
      type: "filetree",
      action: "add",
      isFile: node.isFile,
      path: node.clientPath
    });
  }

  validateName(name)
  {
    let bannedCharRegex = /[\\\/*?"<>|]/;

    if(name.includes(path.sep))
      return `Name can not contain path separators (${path.sep})`;
    if(name == "")
      return "Name can not be blank.";
  }

  cleanName(name)
  {
    let root = path.dirname(require.main.filename);

    // intentionally breaks relative paths
    return path.resolve(name).slice(root.length + 1);
  }

  messageReceived(session, message)
  {
    let node, folder;

    switch(message.action)
    {
    case "add":
      let err = this.createNode(
        message.parentPath,
        message.name,
        message.isFile
      ).catch((err) => {
        session.displayPopup(err);
      });
      break;
    case "delete":
      node = this.getNode(message.path, message.isFile);

      if(node)
        node.delete().catch((err) => {
          session.send(err);
        });
      break;
    case "empty":
      folder = this.getFolder(message.path);

      if(folder)
        folder.empty();
      break;
    case "rename":
      node = this.getNode(message.oldPath, message.isFile);
      let newName = this.cleanName(message.newName);

      let error = this.validateName(newName);

      if(error)
      {
        session.displayPopup(error);
      }
      else
      {
        node.rename(newName).catch((err) => {
          session.displayPopup(err);
        });
      }
      break;
    case "paste":
      folder = this.getFolder(message.parentPath);
      node = this.getNode(message.path, message.isFile);
      let operation = message.cut ? "move" : "copy";
      let destination = folder.clientPath + "/" + node.name;
      let destinationNode = this.getNode(destination, message.isFile);

      if(folder == undefined)
        return;
      if(destinationNode != undefined)
      {
        session.displayPopup(
          `"${destination}" already exists.\n` +
          `Could not move "${message.path}"`
        );
        return;
      }

      fs[operation](node.serverPath, this.parentPath + destination).catch((err) => {
        session.displayPopup(err.message);
      });
      break;
    case "refresh":
      folder = this.getFolder(message.path);

      // folder must've been deleted before we received
      // this message
      if(!folder)
        break;

      // unlist folder if it is not the root
      // otherwise unlist children
      if(folder.parentFolder)
        folder.unlist();
      else
        while(folder.children.length > 0)
          folder.children[0].unlist();

      // restart the filewatcher to repopulate the tree
      this.fileWatcher.restart();
      break;
    }
  }
}

class ServerFileNode extends FileNode
{
  get serverPath()
  {
    return this.filetree.parentPath + this.clientPath;
  }

  async make()
  {
    let fileExists = false;

    await fs.open(this.serverPath, "wx")
      .then((fd) => fs.close(fd))
      .catch((err) => {
        // already exists
        if(err.code == "EEXIST")
          fileExists = true;
        else // failure
          throw err.message;
    });

    if(fileExists)
    {
      let stats = await fs.stat(this.serverPath);

      if(!stats.isFile())
        throw `${this.serverPath} exists as a folder.`;
    }
  }

  async rename(newName)
  {
    let newPath = this.parentFolder == undefined ?
                  this.filetree.parentPath + '/' + newName :
                  this.parentFolder.serverPath + '/' + newName;

    await fs.move(this.serverPath, newPath).catch((err) => {
      throw err.message;
    });

    this.filetree.project.broadcast({
      type: 'filetree',
      action: 'rename',
      oldPath: this.clientPath,
      isFile: this.isFile,
      newName: newName
    });

    this.name = newName;
    this.triggerEvent("rename");
  }

  async delete()
  {
    await fs.remove(this.serverPath)
            .then(() => this.unlink())
            .catch((err) => {
              if(err.code == "ENOENT")
                this.unlink();
              else
                throw err.message;
            });
  }

  unlist()
  {
    if(this.parentFolder != undefined)
      this.filetree.project.broadcast({
        type: "filetree",
        action: "remove",
        isFile: this.isFile,
        path: this.clientPath
      });

    super.unlist();
  }
}

class ServerFolderNode extends ServerFileNode
{
  constructor(filetree, parentFolder, name)
  {
    super(filetree, parentFolder, name);
    this.isFile = false;
    this.children = [];
  }

  async make()
  {
    let fileExists = false;

    await fs.mkdir(this.serverPath).catch((err) => {
      if(err.code == "EEXIST")
        // file exists
        fileExists = true;
      else if(err.code == "ENOENT")
        // folder doesn't exist
        throw `${this.serverPath}  does not exist.`;
      else
        // failure
        throw err.message;
    });

    if(fileExists)
    {
      let stats = await fs.stat(this.serverPath);

      // if it's a file throw an error
      if(stats.isFile())
          throw `${this.serverPath} exists as a file.`;
    }
  }

  registerSubFolder(name)
  {
    let folder = new ServerFolderNode(this.filetree, this, name);
    this.children.push(folder);

    return folder;
  }

  registerFile(name)
  {
    let file = new ServerFileNode(this.filetree, this, name);
    this.children.push(file);

    return file;
  }

  containsChild(name)
  {
    for(let child of this.children)
      if(child.name == name)
        return true;
    return false;
  }

  unlist()
  {
    // unlist children
    while(this.children.length > 0)
      this.children[0].unlist();

    super.unlist();
  }

  async empty()
  {
    let skipped = 0;

    while(this.children.length > skipped)
    {
      // try to delete this child, if it fails
      // increment skipped to skip it
      // failed deletions will remain in the front
      await this.children[skipped].delete().catch(() => skipped++);
    }

    if(skipped > 0)
      throw `${skipped} errors occurred while emptying ${this.clientPath}`
  }
}

module.exports = FileManager;<commit_msg>Fix some error alerts<commit_after>"use strict";

const FileTree = require('../web/public/javascript/shared/filetree');
const FileNode = require('../web/public/javascript/shared/filenode');
const FileWatcher = require('./FileWatcher');
const fs = require('fs-promise');
const path = require('path');

class FileManager extends FileTree
{
  constructor(project)
  {
    super();
    this.root = new ServerFolderNode(this, undefined, project.name);
    this.project = project;
    this.parentPath = "projects/";

    this.root.make();

    this.fileWatcher = new FileWatcher(this);
  }

  sendFolder(session, folder)
  {
    for(let childFolder of folder.children)
    {
      session.send({
        type: "filetree",
        action: "add",
        isFile: childFolder.isFile,
        path: childFolder.clientPath
      });

      if(!childFolder.isFile)
        this.sendFolder(session, childFolder);
    }
  }

  async createNode(parentPath, name, isFile)
  {
    let parentFolder = this.getFolder(parentPath);
    name = this.cleanName(name);
    let nameErrors = this.validateName(name);

    if(!parentFolder)
      throw "Parent folder is undefined.";
    if(parentFolder.containsChild(name))
      throw `${parentPath}/${name} already exists.`;
    if(nameErrors)
      throw nameErrors;

    let node = isFile ? parentFolder.registerFile(name) :
                        parentFolder.registerSubFolder(name);

    await node.make().catch((err) => {
      node.destroy();
      throw err.message;
    });

    this.project.broadcast({
      type: "filetree",
      action: "add",
      isFile: node.isFile,
      path: node.clientPath
    });
  }

  validateName(name)
  {
    let bannedCharRegex = /[\\\/*?"<>|]/;

    if(name.includes(path.sep))
      return `Name can not contain path separators (${path.sep})`;
    if(name == "")
      return "Name can not be blank.";
  }

  cleanName(name)
  {
    let root = path.dirname(require.main.filename);

    // intentionally breaks relative paths
    return path.resolve(name).slice(root.length + 1);
  }

  messageReceived(session, message)
  {
    let node, folder;

    switch(message.action)
    {
    case "add":
      this.createNode(
        message.parentPath,
        message.name,
        message.isFile
      ).catch((err) => {
        session.displayPopup(err);
      });
      break;
    case "delete":
      node = this.getNode(message.path, message.isFile);

      if(node)
        node.delete().catch((err) => {
          session.displayPopup(err);
        });
      break;
    case "empty":
      folder = this.getFolder(message.path);

      if(folder)
        folder.empty();
      break;
    case "rename":
      node = this.getNode(message.oldPath, message.isFile);
      let newName = this.cleanName(message.newName);

      let error = this.validateName(newName);

      if(error)
      {
        session.displayPopup(error);
      }
      else
      {
        node.rename(newName).catch((err) => {
          session.displayPopup(err);
        });
      }
      break;
    case "paste":
      folder = this.getFolder(message.parentPath);
      node = this.getNode(message.path, message.isFile);
      let operation = message.cut ? "move" : "copy";
      let destination = folder.clientPath + "/" + node.name;
      let destinationNode = this.getNode(destination, message.isFile);

      if(folder == undefined)
        return;
      if(destinationNode != undefined)
      {
        session.displayPopup(
          `"${destination}" already exists.\n` +
          `Could not move "${message.path}"`
        );
        return;
      }

      fs[operation](node.serverPath, this.parentPath + destination).catch((err) => {
        session.displayPopup(err.message);
      });
      break;
    case "refresh":
      folder = this.getFolder(message.path);

      // folder must've been deleted before we received
      // this message
      if(!folder)
        break;

      // unlist folder if it is not the root
      // otherwise unlist children
      if(folder.parentFolder)
        folder.unlist();
      else
        while(folder.children.length > 0)
          folder.children[0].unlist();

      // restart the filewatcher to repopulate the tree
      this.fileWatcher.restart();
      break;
    }
  }
}

class ServerFileNode extends FileNode
{
  get serverPath()
  {
    return this.filetree.parentPath + this.clientPath;
  }

  async make()
  {
    let fileExists = false;

    await fs.open(this.serverPath, "wx")
      .then((fd) => fs.close(fd))
      .catch((err) => {
        // already exists
        if(err.code == "EEXIST")
          fileExists = true;
        else // failure
          throw err.message;
    });

    if(fileExists)
    {
      let stats = await fs.stat(this.serverPath);

      if(!stats.isFile())
        throw `${this.serverPath} exists as a folder.`;
    }
  }

  async rename(newName)
  {
    let newPath = this.parentFolder == undefined ?
                  this.filetree.parentPath + '/' + newName :
                  this.parentFolder.serverPath + '/' + newName;

    await fs.move(this.serverPath, newPath).catch((err) => {
      throw err.message;
    });

    this.filetree.project.broadcast({
      type: 'filetree',
      action: 'rename',
      oldPath: this.clientPath,
      isFile: this.isFile,
      newName: newName
    });

    this.name = newName;
    this.triggerEvent("rename");
  }

  async delete()
  {
    await fs.remove(this.serverPath)
            .then(() => this.unlink())
            .catch((err) => {
              if(err.code == "ENOENT")
                this.unlink();
              else
                throw err.message;
            });
  }

  unlist()
  {
    if(this.parentFolder != undefined)
      this.filetree.project.broadcast({
        type: "filetree",
        action: "remove",
        isFile: this.isFile,
        path: this.clientPath
      });

    super.unlist();
  }
}

class ServerFolderNode extends ServerFileNode
{
  constructor(filetree, parentFolder, name)
  {
    super(filetree, parentFolder, name);
    this.isFile = false;
    this.children = [];
  }

  async make()
  {
    let fileExists = false;

    await fs.mkdir(this.serverPath).catch((err) => {
      if(err.code == "EEXIST")
        // file exists
        fileExists = true;
      else if(err.code == "ENOENT")
        // folder doesn't exist
        throw `${this.serverPath}  does not exist.`;
      else
        // failure
        throw err.message;
    });

    if(fileExists)
    {
      let stats = await fs.stat(this.serverPath);

      // if it's a file throw an error
      if(stats.isFile())
          throw `${this.serverPath} exists as a file.`;
    }
  }

  registerSubFolder(name)
  {
    let folder = new ServerFolderNode(this.filetree, this, name);
    this.children.push(folder);

    return folder;
  }

  registerFile(name)
  {
    let file = new ServerFileNode(this.filetree, this, name);
    this.children.push(file);

    return file;
  }

  containsChild(name)
  {
    for(let child of this.children)
      if(child.name == name)
        return true;
    return false;
  }

  unlist()
  {
    // unlist children
    while(this.children.length > 0)
      this.children[0].unlist();

    super.unlist();
  }

  async empty()
  {
    let skipped = 0;

    while(this.children.length > skipped)
    {
      // try to delete this child, if it fails
      // increment skipped to skip it
      // failed deletions will remain in the front
      await this.children[skipped].delete().catch(() => skipped++);
    }

    if(skipped > 0)
      throw `${skipped} errors occurred while emptying ${this.clientPath}`
  }
}

module.exports = FileManager;<|endoftext|>


<commit_before>/**
 * Name: Users
 * Description: Track known users
 */
var users = function(dbot) {
    var knownUsers = dbot.db.knownUsers;
    var getServerUsers = function(event) {
        if(!knownUsers.hasOwnProperty(event.server)) {
            knownUsers[event.server] = { 'users': [], 'aliases': {} };
        }
        return knownUsers[event.server];
    };

    dbot.instance.addListener('366', 'users', function(event) {
        var knownUsers = getServerUsers(event);
        for(var nick in event.channel.nicks) {
            if(!knownUsers.users.include(nick) && !knownUsers.aliases.hasOwnProperty(nick) &&
                    event.channel.nicks.hasOwnProperty(nick)) {
                knownUsers.users.push(nick);
            }
        }
    });

    return {
        'name': 'users',
        'ignorable': false,

        'commands': {
            '~alias': function(event) {
                var knownUsers = getServerUsers(event);
                var alias = event.params[1].trim();
                if(knownUsers.aliases.hasOwnProperty(alias)) {
                    event.reply(alias + ' is an alias of ' + knownUsers.aliases[alias]);
                } else {
                    event.reply(alias + ' is not known as an alias to me.');
                }
            }
        },

        'listener': function(event) {
            var knownUsers = getServerUsers(event);
            if(event.action == 'JOIN') {
                if(!knownUsers.users.include(event.user)) {
                    knownUsers.users.push(event.user);
                }
            } else if(event.action == 'NICK') {
                var newNick = event.params.substr(1);
                if(!knownUsers.users.include(newNick)) {
                    knownUsers.aliases[newNick] = event.user;
                }
            }
        },
        'on': ['JOIN', 'NICK'],

        'onLoad': function() {
            // Trigger updateNickLists to stat current users in channel
            var connections = dbot.instance.connections;
            for(var conn in connections) {
                if(connections.hasOwnProperty(conn)) {
                    connections[conn].updateNickLists();
                }
            }
        }
    };
};

exports.fetch = function(dbot) {
    return users(dbot);
};
<commit_msg>Add ~setaliasparent command [#83]<commit_after>/**
 * Name: Users
 * Description: Track known users
 */
var users = function(dbot) {
    var knownUsers = dbot.db.knownUsers;
    var getServerUsers = function(event) {
        if(!knownUsers.hasOwnProperty(event.server)) {
            knownUsers[event.server] = { 'users': [], 'aliases': {} };
        }
        return knownUsers[event.server];
    };

    dbot.instance.addListener('366', 'users', function(event) {
        var knownUsers = getServerUsers(event);
        for(var nick in event.channel.nicks) {
            if(!knownUsers.users.include(nick) && !knownUsers.aliases.hasOwnProperty(nick) &&
                    event.channel.nicks.hasOwnProperty(nick)) {
                knownUsers.users.push(nick);
            }
        }
    });

    var commands = {
        '~alias': function(event) {
            var knownUsers = getServerUsers(event);
            var alias = event.params[1].trim();
            if(knownUsers.aliases.hasOwnProperty(alias)) {
                event.reply(alias + ' is an alias of ' + knownUsers.aliases[alias]);
            } else {
                event.reply(alias + ' is not known as an alias to me.');
            }
        },

        '~setaliasparent': function(event) {
            if(dbot.config.admins.include(event.user)) {
                var knownUsers = getServerUsers(event);
                var newParent = event.params[1];

                if(knownUsers.aliases.hasOwnProperty(newParent)) {
                    var newAlias = knownUsers.aliases[newParent];

                    // Replace users entry with new primary user
                    var usersIndex = knownUsers.users.indexOf(newAlias);
                    knownUsers.users[usersIndex] = newParent;

                    // Remove alias for new parent & add alias for new alias
                    delete knownUsers.aliases[newParent];
                    knownUsers.aliases[newAlias] = newParent;

                    // Update aliases to point to new primary user
                    for(var alias in knownUsers.aliases) {
                        if(knownUsers.aliases.hasOwnProperty(alias)) {
                            if(knownUsers.aliases[alias] === newAlias) {
                                knownUsers.aliases[alias] = newParent;
                            }
                        }
                    }

                    event.reply(newParent + ' is now the parent user, and ' +
                        newAlias + ' is an alias.');
                } else {
                    event.reply('Given new parent does not currently exist as an alias.');
                }
            }
        }
    };

    return {
        'name': 'users',
        'ignorable': false,
        'commands': commands,

        'listener': function(event) {
            var knownUsers = getServerUsers(event);
            if(event.action == 'JOIN') {
                if(!knownUsers.users.include(event.user)) {
                    knownUsers.users.push(event.user);
                }
            } else if(event.action == 'NICK') {
                var newNick = event.params.substr(1);
                if(!knownUsers.users.include(newNick)) {
                    knownUsers.aliases[newNick] = event.user;
                }
            }
        },
        'on': ['JOIN', 'NICK'],

        'onLoad': function() {
            // Trigger updateNickLists to stat current users in channel
            var connections = dbot.instance.connections;
            for(var conn in connections) {
                if(connections.hasOwnProperty(conn)) {
                    connections[conn].updateNickLists();
                }
            }
        }
    };
};

exports.fetch = function(dbot) {
    return users(dbot);
};
<|endoftext|>