<commit_before>import debug from 'debug';
import path from 'path';
import fs from 'fs-promise';
import Promise from 'bluebird';
import ArchieConverter from './archie-converter';
import SpreadsheetConverter from './spreadsheet-converter';
import moment from 'moment';
import EventEmitter from 'events';
import zip from 'lodash.zip';
import streamBuffers from 'stream-buffers';

const log = debug('google-drive-sync:syncer');

const mimeTypes = [
    'application/vnd.google-apps.spreadsheet',
    'application/vnd.google-apps.document'
];

const maxItemsInState = 100;
const IGNORED_ERRORS = [429];

export default class Syncer {
    constructor(opts) {
        this.client = opts.client;
        this.outputDirectories = opts.outputDirectory.split(',');

        if (!opts.state) {
            throw new Error(`must specify "state" option`)
        }

        this.stateFile = opts.state;
        this.events = new EventEmitter();
    }

    sync() {
        this.events.emit('sync');
        const fetchState = fs.readFile(this.stateFile, 'utf-8').catch(err => null).then(JSON.parse)

        return Promise.join(
            fetchState,
            this.client.authorize(), // TODO: re-use JWT tokens but handle expiry
            (state) => {
                return this.ensurePageTokenIn(state || {pageToken: null, docs: {}})
                    .then(state => this.fetchChanges(state))
        });
    }

    fetchChanges(state) {
        return this.client
            .getChanges(state.pageToken)
            .then(list => this.handleChanges(state, list))
            .then(::this.fetchSpecialFiles)
            .catch(err => this.events.emit('error', err));

    }

    ensurePageTokenIn(state) {
        if (state.pageToken) {
            return Promise.resolve(state);
        } else {
            return this.client
                .getStartPageToken()
                .then(res => this.updateState({...state, pageToken: res.startPageToken}))
        }
    }

    on(...args) {
        this.events.on(...args);
    }

    handleChanges(state, list) {
        const ids = new Set();

        list.changes
            .filter(i => {
                return !i.removed && mimeTypes.indexOf(i.file.mimeType) !== -1
            })
            .forEach(i => {
                state.docs[i.fileId] = i.file;
                ids.add(i.fileId);
            });

        return Promise.map(
            Array.from(ids),
            id => this.client.getFile(id).then(::this.downloadFile),
            {concurrency: 3}
        )
        .then(() => this.updateState({
            ...state,
            pageToken: list.nextPageToken || list.newStartPageToken,
            lastCheck: moment().format()
        }))
        .then(state => this.events.emit('synced', state))
        .then(() => ids);
    }

    fetchSpecialFiles() {
        const ids = process.env.GDRIVE_ALWAYS_FETCH ? process.env.GDRIVE_ALWAYS_FETCH.split(',') : []

        return Promise.map(
            ids,
            id => this.client.getFile(id).then(::this.downloadFile),
            {concurrency: 1}
        )
    }

    updateState(state) {
        const ids = Object.keys(state.docs);

        if (ids.length > maxItemsInState) {
            ids
                .sort((a, b) => moment(state.docs[b].modifiedDate).valueOf() - moment(state.docs[a].modifiedDate).valueOf())
                .slice(maxItemsInState)
                .forEach(id => delete state.docs[id])
        }

        return fs.writeFile(this.stateFile, JSON.stringify(state)).then(() => state);
    }

    downloadFile(file) {
        let promise = null;

        switch (file.mimeType) {
            case 'application/vnd.google-apps.spreadsheet':
                promise = this.convertSpreadsheet(file).then(data => ([{fileName: file.id, data}]));
                break;
            case 'application/vnd.google-apps.document':
                promise = this.convertDocument(file).then(results => ([
                    {fileName: file.id, data: results.plain},
                    {fileName: `${file.id}.styled`, data: results.styled},
                ]))

                break;
            default:
                throw new Error(`unknown mime type: ${file.mimeType}`)

        };

        const modification = this.getModification(file);

        return promise
            .then(results => {
                return Promise.each(
                    results,
                    ({fileName, data}) => this.save(fileName, { modification, data })
                )
            })
            .catch(err => {
                console.error(file.webViewLink, err.message);
                this.events.emit('error', err);

                let isIgnored = err.httpResponse && IGNORED_ERRORS.includes(err.httpResponse.statusCode);
                isIgnored = isIgnored || !!err.isArchieMLError;

                if (isIgnored) {
                    log('error ignored');
                    return null;
                } else {
                    throw err;
                }
            });
    }

    convertSpreadsheet(doc) {
        return new Promise((resolve, reject) => {
            const stream = this.client.getExportFileStream(doc.id, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
            const writable = new streamBuffers.WritableStreamBuffer();

            stream
                .on('end', () => {
                    log('end stream');
                    const buf = writable.getContents();
                    writable.end();
                    resolve(buf);
                })
                .on('error', reject)
                .pipe(writable);
        }).then(buf => SpreadsheetConverter.convert(buf.toString('binary')))
    }

    convertDocument(doc) {
        return this.client.exportFile(doc.id, 'text/html')
            .then(html => Promise.props({
                plain: ArchieConverter.convert(html),
                styled: ArchieConverter.convert(html, {preserve_styles: ['bold', 'italic', 'underline']})
            }));
    }

    getModification(doc) {
        return {
            user: {
                name: doc.lastModifyingUser.displayName,
                email: doc.lastModifyingUser.emailAddress
            },
            date: doc.modifiedTime,
            version: doc.version
        };
    }

    save(name, data) {
        const fileName = `${name}.json`;

        if (data === null) {
            // probably an operational error - don't write the file
            return Promise.resolve();
        }

        return Promise.map(this.outputDirectories, dir => {
            const filePath = path.join(dir, fileName);

            return fs
                .writeFile(filePath, JSON.stringify(data))
                .then(() => this.events.emit('saved', fileName, data));
        });
    }

    log(obj) {
        log(JSON.stringify(obj, null, 2));
    }
}<commit_msg>Include downloadTime and downloadLag in meta data<commit_after>import debug from 'debug';
import path from 'path';
import fs from 'fs-promise';
import Promise from 'bluebird';
import ArchieConverter from './archie-converter';
import SpreadsheetConverter from './spreadsheet-converter';
import moment from 'moment';
import EventEmitter from 'events';
import zip from 'lodash.zip';
import streamBuffers from 'stream-buffers';

const log = debug('google-drive-sync:syncer');

const mimeTypes = [
    'application/vnd.google-apps.spreadsheet',
    'application/vnd.google-apps.document'
];

const maxItemsInState = 100;
const IGNORED_ERRORS = [429];

export default class Syncer {
    constructor(opts) {
        this.client = opts.client;
        this.outputDirectories = opts.outputDirectory.split(',');

        if (!opts.state) {
            throw new Error(`must specify "state" option`)
        }

        this.stateFile = opts.state;
        this.events = new EventEmitter();
    }

    sync() {
        this.events.emit('sync');
        const fetchState = fs.readFile(this.stateFile, 'utf-8').catch(err => null).then(JSON.parse)

        return Promise.join(
            fetchState,
            this.client.authorize(), // TODO: re-use JWT tokens but handle expiry
            (state) => {
                return this.ensurePageTokenIn(state || {pageToken: null, docs: {}})
                    .then(state => this.fetchChanges(state))
        });
    }

    fetchChanges(state) {
        return this.client
            .getChanges(state.pageToken)
            .then(list => this.handleChanges(state, list))
            .then(::this.fetchSpecialFiles)
            .catch(err => this.events.emit('error', err));

    }

    ensurePageTokenIn(state) {
        if (state.pageToken) {
            return Promise.resolve(state);
        } else {
            return this.client
                .getStartPageToken()
                .then(res => this.updateState({...state, pageToken: res.startPageToken}))
        }
    }

    on(...args) {
        this.events.on(...args);
    }

    handleChanges(state, list) {
        const ids = new Set();

        list.changes
            .filter(i => {
                return !i.removed && mimeTypes.indexOf(i.file.mimeType) !== -1
            })
            .forEach(i => {
                state.docs[i.fileId] = i.file;
                ids.add(i.fileId);
            });

        return Promise.map(
            Array.from(ids),
            id => this.client.getFile(id).then(::this.downloadFile),
            {concurrency: 3}
        )
        .then(() => this.updateState({
            ...state,
            pageToken: list.nextPageToken || list.newStartPageToken,
            lastCheck: moment().format()
        }))
        .then(state => this.events.emit('synced', state))
        .then(() => ids);
    }

    fetchSpecialFiles() {
        const ids = process.env.GDRIVE_ALWAYS_FETCH ? process.env.GDRIVE_ALWAYS_FETCH.split(',') : []

        return Promise.map(
            ids,
            id => this.client.getFile(id).then(::this.downloadFile),
            {concurrency: 1}
        )
    }

    updateState(state) {
        const ids = Object.keys(state.docs);

        if (ids.length > maxItemsInState) {
            ids
                .sort((a, b) => moment(state.docs[b].modifiedDate).valueOf() - moment(state.docs[a].modifiedDate).valueOf())
                .slice(maxItemsInState)
                .forEach(id => delete state.docs[id])
        }

        return fs.writeFile(this.stateFile, JSON.stringify(state)).then(() => state);
    }

    downloadFile(file) {
        let promise = null;

        switch (file.mimeType) {
            case 'application/vnd.google-apps.spreadsheet':
                promise = this.convertSpreadsheet(file).then(data => ([{fileName: file.id, data}]));
                break;
            case 'application/vnd.google-apps.document':
                promise = this.convertDocument(file).then(results => ([
                    {fileName: file.id, data: results.plain},
                    {fileName: `${file.id}.styled`, data: results.styled},
                ]))

                break;
            default:
                throw new Error(`unknown mime type: ${file.mimeType}`)

        };

        const modification = this.getModification(file);

        return promise
            .then(results => {
                return Promise.each(
                    results,
                    ({fileName, data}) => this.save(fileName, { modification, data })
                )
            })
            .catch(err => {
                console.error(file.webViewLink, err.message);
                this.events.emit('error', err);

                let isIgnored = err.httpResponse && IGNORED_ERRORS.includes(err.httpResponse.statusCode);
                isIgnored = isIgnored || !!err.isArchieMLError;

                if (isIgnored) {
                    log('error ignored');
                    return null;
                } else {
                    throw err;
                }
            });
    }

    convertSpreadsheet(doc) {
        return new Promise((resolve, reject) => {
            const stream = this.client.getExportFileStream(doc.id, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
            const writable = new streamBuffers.WritableStreamBuffer();

            stream
                .on('end', () => {
                    log('end stream');
                    const buf = writable.getContents();
                    writable.end();
                    resolve(buf);
                })
                .on('error', reject)
                .pipe(writable);
        }).then(buf => SpreadsheetConverter.convert(buf.toString('binary')))
    }

    convertDocument(doc) {
        return this.client.exportFile(doc.id, 'text/html')
            .then(html => Promise.props({
                plain: ArchieConverter.convert(html),
                styled: ArchieConverter.convert(html, {preserve_styles: ['bold', 'italic', 'underline']})
            }));
    }

    getModification(doc) {
        const now = moment();
        const modified = moment(doc.modifiedTime);
        const lag = moment.duration(now.diff(modified));

        return {
            user: {
                name: doc.lastModifyingUser.displayName,
                email: doc.lastModifyingUser.emailAddress
            },
            date: modified.format(),
            version: doc.version,
            downloadTime: now.format(),
            downloadLag: {
                ms: lag.valueOf(),
                human: lag.humanize()
            }
        };
    }

    save(name, data) {
        const fileName = `${name}.json`;

        if (data === null) {
            // probably an operational error - don't write the file
            return Promise.resolve();
        }

        return Promise.map(this.outputDirectories, dir => {
            const filePath = path.join(dir, fileName);

            return fs
                .writeFile(filePath, JSON.stringify(data))
                .then(() => this.events.emit('saved', fileName, data));
        });
    }

    log(obj) {
        log(JSON.stringify(obj, null, 2));
    }
}<|endoftext|>


<commit_before>var page = require('webpage').create(),
    async = require('./async.js'),
    downloadLink;

function errorFn(msg, trace) {
  // Log the error and trace
  var system = require('system');
  system.stderr.write('What\'s up?');
  // trace.forEach(function(item) {
  //     console.error('  ', item.file, ':', item.line);
  // });

  // Leave with a bad exit code
  phantom.exit(1);
}
phantom.onError = errorFn;
page.onError = errorFn;

// Run a check function every 100 ms
function waitFor(checkFn, cb) {
  throw new Error('hai');
  if (checkFn()) {
    cb();
  } else {
    setTimeout(function waitForFn () {
      waitFor(checkFn, cb);
    }, 100);
  }
}

function openIcoMoon(cb) {
  // Open IcoMoon
  page.open('http://icomoon.io/app-old', function (status) {
    // If the status was 'fail', callback with an error
    var err = null;
    if (status === 'fail') {
      err = new Error('IcoMoon app "http://icomoon.io/app-old" could not be opened.');
    }
    cb(err);
  });
}
function waitForLoading(cb) {
  // Wait for loading to complete
  waitFor(function () {
    return page.evaluate(function () {
      return !document.getElementById('loading');
    });
  }, cb);
}

// In series
async.series([
  // On first open, cache bust
  openIcoMoon,
  waitForLoading,
  function clearCache (cb) {
    // Clear out indexedDB and localStorage
    page.evaluate(function () {
      if (window.indexedDB) {
        indexedDB.deleteDatabase('IDBWrapper-storage');
      }

      if (window.localStorage) {
        localStorage.clear();
      }
    });

    // Callback
    cb();
  },
  // Re-open page with busted cache
  openIcoMoon,
  waitForLoading,
  function uploadImages (cb) {
    // Submit many images (need a file path for all our images)
    var fs = require('fs'),
        filesPath = phantom.args[0],
        filesJSON = fs.read(filesPath),
        files = JSON.parse(filesJSON);
    page.uploadFile('#files', files);

    // Continue
    waitFor(function () {
      var itemsCreated = page.evaluate(function () {
        return $('#imported').find('.checkbox-icon').length;
      });
      return itemsCreated === files.length;
    }, cb);
  },
  function moveToDownloadScreen (cb) {
    // Move to the downlod screen
    page.evaluate(function () {
      // Select our images
      $('#imported').find('.checkbox-icon').click();

      // "Click" the 'Next' link
      window.location.hash = 'font';
    });

    // Wait for the next screen to load
    waitFor(function () {
      return page.evaluate(function () {
        return $('#saveFont').length;
      });
    }, cb);
  },
  function exportFont (cb) {
    // Save any zip redirect requests
    page.onNavigationRequested = function (url) {
      if (url.indexOf('.zip') > -1) {
        downloadLink = url;
      }
    };

    // Click the download link
    page.evaluate(function () {
      $('#saveFont').click();
    });

    // Wait for the redirect request to our zip
    waitFor(function () {
      return downloadLink;
    }, cb);
  }
], function output (err) {
  // // DEV: Take a screenshot for progress
  // page.render('app.png');

  // If there was an error, log it
  if (err) {
    console.error(err);
    phantom.exit(1);
  } else {
  // Otherwise, output the download link for the next module
    console.log(downloadLink);
    phantom.exit(0);
  }
});
<commit_msg>Getting a valid trace<commit_after>var system = require('system'),
    page = require('webpage').create(),
    async = require('./async.js'),
    downloadLink;

function errorFn(msg, trace) {
  // Log the error and trace
  system.stderr.writeLine(msg);
  trace.forEach(function(item) {
    system.stderr.writeLine('  ' + item.file + ':' + item.line);
  });

  // Leave with a bad exit code
  phantom.exit(1);
}
phantom.onError = errorFn;
page.onError = errorFn;

// Run a check function every 100 ms
function waitFor(checkFn, cb) {
  throw new Error('hai');
  if (checkFn()) {
    cb();
  } else {
    setTimeout(function waitForFn () {
      waitFor(checkFn, cb);
    }, 100);
  }
}

function openIcoMoon(cb) {
  // Open IcoMoon
  page.open('http://icomoon.io/app-old', function (status) {
    // If the status was 'fail', callback with an error
    var err = null;
    if (status === 'fail') {
      err = new Error('IcoMoon app "http://icomoon.io/app-old" could not be opened.');
    }
    cb(err);
  });
}
function waitForLoading(cb) {
  // Wait for loading to complete
  waitFor(function () {
    return page.evaluate(function () {
      return !document.getElementById('loading');
    });
  }, cb);
}

// In series
async.series([
  // On first open, cache bust
  openIcoMoon,
  waitForLoading,
  function clearCache (cb) {
    // Clear out indexedDB and localStorage
    page.evaluate(function () {
      if (window.indexedDB) {
        indexedDB.deleteDatabase('IDBWrapper-storage');
      }

      if (window.localStorage) {
        localStorage.clear();
      }
    });

    // Callback
    cb();
  },
  // Re-open page with busted cache
  openIcoMoon,
  waitForLoading,
  function uploadImages (cb) {
    // Submit many images (need a file path for all our images)
    var fs = require('fs'),
        filesPath = phantom.args[0],
        filesJSON = fs.read(filesPath),
        files = JSON.parse(filesJSON);
    page.uploadFile('#files', files);

    // Continue
    waitFor(function () {
      var itemsCreated = page.evaluate(function () {
        return $('#imported').find('.checkbox-icon').length;
      });
      return itemsCreated === files.length;
    }, cb);
  },
  function moveToDownloadScreen (cb) {
    // Move to the downlod screen
    page.evaluate(function () {
      // Select our images
      $('#imported').find('.checkbox-icon').click();

      // "Click" the 'Next' link
      window.location.hash = 'font';
    });

    // Wait for the next screen to load
    waitFor(function () {
      return page.evaluate(function () {
        return $('#saveFont').length;
      });
    }, cb);
  },
  function exportFont (cb) {
    // Save any zip redirect requests
    page.onNavigationRequested = function (url) {
      if (url.indexOf('.zip') > -1) {
        downloadLink = url;
      }
    };

    // Click the download link
    page.evaluate(function () {
      $('#saveFont').click();
    });

    // Wait for the redirect request to our zip
    waitFor(function () {
      return downloadLink;
    }, cb);
  }
], function output (err) {
  // // DEV: Take a screenshot for progress
  // page.render('app.png');

  // If there was an error, log it
  if (err) {
    console.error(err);
    phantom.exit(1);
  } else {
  // Otherwise, output the download link for the next module
    console.log(downloadLink);
    phantom.exit(0);
  }
});
<|endoftext|>


<commit_before>/** @babel */
/** @jsx etch.dom */

import fs from 'fs-plus'
import {Emitter, CompositeDisposable, Disposable} from 'atom'
import etch from 'etch'

// View that renders the image of an {ImageEditor}.
export default class ImageEditorView {
  constructor (editor) {
    this.editor = editor
    this.emitter = new Emitter()
    this.disposables = new CompositeDisposable()
    this.imageSize = fs.statSync(this.editor.getPath()).size
    this.loaded = false
    this.mode = 'zoom-to-fit'
    this.percentageStep = 4
    this.steps = [0.1, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 2, 3, 4, 5, 7.5, 10]
    etch.initialize(this)

    this.refs.image.style.display = 'none'
    this.updateImageURI()

    this.disposables.add(this.editor.onDidChange(() => this.updateImageURI()))
    this.disposables.add(atom.commands.add(this.element, {
      'image-view:reload': () => this.updateImageURI(),
      'image-view:zoom-in': () => this.zoomIn(),
      'image-view:zoom-out': () => this.zoomOut(),
      'image-view:zoom-to-fit': () => this.zoomToFit(),
      'image-view:reset-zoom': () => this.resetZoom(),
      'core:move-up': () => { this.scrollUp() },
      'core:move-down': () => { this.scrollDown() },
      'core:page-up': () => { this.pageUp() },
      'core:page-down': () => { this.pageDown() },
      'core:move-to-top': () => { this.scrollToTop() },
      'core:move-to-bottom': () => { this.scrollToBottom() }
    }))

    this.refs.image.onload = () => {
      this.refs.image.onload = null
      this.originalHeight = this.refs.image.naturalHeight
      this.originalWidth = this.refs.image.naturalWidth
      this.loaded = true
      this.refs.image.style.display = ''
      defaultBackgroundColor = atom.config.get('image-view.defaultBackgroundColor')
      this.refs.imageContainer.setAttribute('background', defaultBackgroundColor)
      this.emitter.emit('did-load')
    }

    this.disposables.add(atom.tooltips.add(this.refs.whiteTransparentBackgroundButton, {title: 'Use white transparent background'}))
    this.disposables.add(atom.tooltips.add(this.refs.blackTransparentBackgroundButton, {title: 'Use black transparent background'}))
    this.disposables.add(atom.tooltips.add(this.refs.transparentTransparentBackgroundButton, {title: 'Use transparent background'}))

    const clickHandler = (event) => {
      event.preventDefault()
      event.stopPropagation()
      this.changeBackground(event.target.value)
    }

    this.refs.whiteTransparentBackgroundButton.addEventListener('click', clickHandler)
    this.disposables.add(new Disposable(() => { this.refs.whiteTransparentBackgroundButton.removeEventListener('click', clickHandler) }))
    this.refs.blackTransparentBackgroundButton.addEventListener('click', clickHandler)
    this.disposables.add(new Disposable(() => { this.refs.blackTransparentBackgroundButton.removeEventListener('click', clickHandler) }))
    this.refs.transparentTransparentBackgroundButton.addEventListener('click', clickHandler)
    this.disposables.add(new Disposable(() => { this.refs.transparentTransparentBackgroundButton.removeEventListener('click', clickHandler) }))

    const zoomInClickHandler = () => {
      this.zoomIn()
    }
    this.refs.zoomInButton.addEventListener('click', zoomInClickHandler)
    this.disposables.add(new Disposable(() => { this.refs.zoomInButton.removeEventListener('click', zoomInClickHandler) }))

    const zoomOutClickHandler = () => {
      this.zoomOut()
    }
    this.refs.zoomOutButton.addEventListener('click', zoomOutClickHandler)
    this.disposables.add(new Disposable(() => { this.refs.zoomOutButton.removeEventListener('click', zoomOutClickHandler) }))

    const resetZoomClickHandler = () => {
      this.resetZoom()
    }
    this.refs.resetZoomButton.addEventListener('click', resetZoomClickHandler)
    this.disposables.add(new Disposable(() => { this.refs.resetZoomButton.removeEventListener('click', resetZoomClickHandler) }))

    const zoomToFitClickHandler = () => {
      this.zoomToFit()
    }
    this.refs.zoomToFitButton.addEventListener('click', zoomToFitClickHandler)
    this.disposables.add(new Disposable(() => { this.refs.zoomToFitButton.removeEventListener('click', zoomToFitClickHandler) }))
  }

  onDidLoad (callback) {
    return this.emitter.on('did-load', callback)
  }

  update () {}

  destroy () {
    this.disposables.dispose()
    this.emitter.dispose()
    return etch.destroy(this)
  }

  render () {
    return (

            white
            black
            transparent

            <button className='btn' ref='zoomOutButton'>-</button>
            <button className='btn reset-zoom-button' ref='resetZoomButton'>Auto</button>
            <button className='btn' ref='zoomInButton'>+</button>

            <button className='btn zoom-to-fit-button selected' ref='zoomToFitButton'>Zoom to fit</button>

    )
  }

  updateImageURI () {
    this.refs.image.src = `${this.editor.getEncodedURI()}?time=${Date.now()}`
  }

  // Zooms the image out by 25%.
  zoomOut () {
    this.percentageStep = Math.max(0, --this.percentageStep)
    this.adjustSize(this.percentageStep)
  }

  // Zooms the image in by 25%.
  zoomIn () {
    this.percentageStep = Math.min(this.steps.length - 1, ++this.percentageStep)
    this.adjustSize(this.percentageStep)
  }

  // Zooms the image to its normal width and height.
  resetZoom () {
    if (!this.loaded || this.element.offsetHeight === 0) {
      return
    }

    this.mode = 'reset-zoom'
    this.refs.imageContainer.classList.remove('zoom-to-fit')
    this.refs.zoomToFitButton.classList.remove('selected')
    this.refs.image.style.width = this.originalWidth + 'px'
    this.refs.image.style.height = this.originalHeight + 'px'
    this.refs.resetZoomButton.textContent = '100%'
    this.percentageStep = 4
  }

  // Zooms to fit the image, doesn't scale beyond actual size
  zoomToFit () {
    if (!this.loaded || this.element.offsetHeight === 0) {
      return
    }

    this.mode = 'zoom-to-fit'
    this.refs.imageContainer.classList.add('zoom-to-fit')
    this.refs.zoomToFitButton.classList.add('selected')
    this.refs.image.style.width = ''
    this.refs.image.style.height = ''
    this.refs.resetZoomButton.textContent = 'Auto'
    this.percentageStep = 4
  }

  // Adjust the size of the image by the given multiplying factor.
  //
  // factor - A {Number} to multiply against the current size.
  adjustSize (percentageStep) {
    if (!this.loaded || this.element.offsetHeight === 0) {
      return
    }

    if (this.mode === 'zoom-to-fit') {
      this.mode = 'zoom-manual'
      this.refs.imageContainer.classList.remove('zoom-to-fit')
      this.refs.zoomToFitButton.classList.remove('selected')
    } else if (this.mode === 'reset-zoom') {
      this.mode = 'zoom-manual'
    }

    const factor = this.steps[percentageStep]
    const newWidth = this.originalWidth * factor
    const newHeight = this.originalHeight * factor
    const percent = Math.max(1, Math.round((newWidth / this.originalWidth) * 100))

    // Switch to pixelated rendering when image is bigger than 200%
    if (newWidth > (this.originalWidth * 2)) {
      this.refs.image.style.imageRendering = 'pixelated'
    } else {
      this.refs.image.style.imageRendering = ''
    }

    this.refs.image.style.width = newWidth + 'px'
    this.refs.image.style.height = newHeight + 'px'
    this.refs.resetZoomButton.textContent = percent + '%'
  }

  // Changes the background color of the image view.
  //
  // color - A {String} that gets used as class name.
  changeBackground (color) {
    if (this.loaded && this.element.offsetHeight > 0 && color) {
      this.refs.imageContainer.setAttribute('background', color)
    }
  }

  scrollUp () {
    this.refs.imageContainer.scrollTop -= document.body.offsetHeight / 20
  }

  scrollDown () {
    this.refs.imageContainer.scrollTop += document.body.offsetHeight / 20
  }

  pageUp () {
    this.refs.imageContainer.scrollTop -= this.element.offsetHeight
  }

  pageDown () {
    this.refs.imageContainer.scrollTop += this.element.offsetHeight
  }

  scrollToTop () {
    this.refs.imageContainer.scrollTop = 0
  }

  scrollToBottom () {
    this.refs.imageContainer.scrollTop = this.refs.imageContainer.scrollHeight
  }
}
<commit_msg>Remove global background colour variable<commit_after>/** @babel */
/** @jsx etch.dom */

import fs from 'fs-plus'
import {Emitter, CompositeDisposable, Disposable} from 'atom'
import etch from 'etch'

// View that renders the image of an {ImageEditor}.
export default class ImageEditorView {
  constructor (editor) {
    this.editor = editor
    this.emitter = new Emitter()
    this.disposables = new CompositeDisposable()
    this.imageSize = fs.statSync(this.editor.getPath()).size
    this.loaded = false
    this.mode = 'zoom-to-fit'
    this.percentageStep = 4
    this.steps = [0.1, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 2, 3, 4, 5, 7.5, 10]
    etch.initialize(this)

    this.refs.image.style.display = 'none'
    this.updateImageURI()

    this.disposables.add(this.editor.onDidChange(() => this.updateImageURI()))
    this.disposables.add(atom.commands.add(this.element, {
      'image-view:reload': () => this.updateImageURI(),
      'image-view:zoom-in': () => this.zoomIn(),
      'image-view:zoom-out': () => this.zoomOut(),
      'image-view:zoom-to-fit': () => this.zoomToFit(),
      'image-view:reset-zoom': () => this.resetZoom(),
      'core:move-up': () => { this.scrollUp() },
      'core:move-down': () => { this.scrollDown() },
      'core:page-up': () => { this.pageUp() },
      'core:page-down': () => { this.pageDown() },
      'core:move-to-top': () => { this.scrollToTop() },
      'core:move-to-bottom': () => { this.scrollToBottom() }
    }))

    this.refs.image.onload = () => {
      this.refs.image.onload = null
      this.originalHeight = this.refs.image.naturalHeight
      this.originalWidth = this.refs.image.naturalWidth
      this.loaded = true
      this.refs.image.style.display = ''
      this.defaultBackgroundColor = atom.config.get('image-view.defaultBackgroundColor')
      this.refs.imageContainer.setAttribute('background', this.defaultBackgroundColor)
      this.emitter.emit('did-load')
    }

    this.disposables.add(atom.tooltips.add(this.refs.whiteTransparentBackgroundButton, {title: 'Use white transparent background'}))
    this.disposables.add(atom.tooltips.add(this.refs.blackTransparentBackgroundButton, {title: 'Use black transparent background'}))
    this.disposables.add(atom.tooltips.add(this.refs.transparentTransparentBackgroundButton, {title: 'Use transparent background'}))

    const clickHandler = (event) => {
      event.preventDefault()
      event.stopPropagation()
      this.changeBackground(event.target.value)
    }

    this.refs.whiteTransparentBackgroundButton.addEventListener('click', clickHandler)
    this.disposables.add(new Disposable(() => { this.refs.whiteTransparentBackgroundButton.removeEventListener('click', clickHandler) }))
    this.refs.blackTransparentBackgroundButton.addEventListener('click', clickHandler)
    this.disposables.add(new Disposable(() => { this.refs.blackTransparentBackgroundButton.removeEventListener('click', clickHandler) }))
    this.refs.transparentTransparentBackgroundButton.addEventListener('click', clickHandler)
    this.disposables.add(new Disposable(() => { this.refs.transparentTransparentBackgroundButton.removeEventListener('click', clickHandler) }))

    const zoomInClickHandler = () => {
      this.zoomIn()
    }
    this.refs.zoomInButton.addEventListener('click', zoomInClickHandler)
    this.disposables.add(new Disposable(() => { this.refs.zoomInButton.removeEventListener('click', zoomInClickHandler) }))

    const zoomOutClickHandler = () => {
      this.zoomOut()
    }
    this.refs.zoomOutButton.addEventListener('click', zoomOutClickHandler)
    this.disposables.add(new Disposable(() => { this.refs.zoomOutButton.removeEventListener('click', zoomOutClickHandler) }))

    const resetZoomClickHandler = () => {
      this.resetZoom()
    }
    this.refs.resetZoomButton.addEventListener('click', resetZoomClickHandler)
    this.disposables.add(new Disposable(() => { this.refs.resetZoomButton.removeEventListener('click', resetZoomClickHandler) }))

    const zoomToFitClickHandler = () => {
      this.zoomToFit()
    }
    this.refs.zoomToFitButton.addEventListener('click', zoomToFitClickHandler)
    this.disposables.add(new Disposable(() => { this.refs.zoomToFitButton.removeEventListener('click', zoomToFitClickHandler) }))
  }

  onDidLoad (callback) {
    return this.emitter.on('did-load', callback)
  }

  update () {}

  destroy () {
    this.disposables.dispose()
    this.emitter.dispose()
    return etch.destroy(this)
  }

  render () {
    return (

            white
            black
            transparent

            <button className='btn' ref='zoomOutButton'>-</button>
            <button className='btn reset-zoom-button' ref='resetZoomButton'>Auto</button>
            <button className='btn' ref='zoomInButton'>+</button>

            <button className='btn zoom-to-fit-button selected' ref='zoomToFitButton'>Zoom to fit</button>

    )
  }

  updateImageURI () {
    this.refs.image.src = `${this.editor.getEncodedURI()}?time=${Date.now()}`
  }

  // Zooms the image out by 25%.
  zoomOut () {
    this.percentageStep = Math.max(0, --this.percentageStep)
    this.adjustSize(this.percentageStep)
  }

  // Zooms the image in by 25%.
  zoomIn () {
    this.percentageStep = Math.min(this.steps.length - 1, ++this.percentageStep)
    this.adjustSize(this.percentageStep)
  }

  // Zooms the image to its normal width and height.
  resetZoom () {
    if (!this.loaded || this.element.offsetHeight === 0) {
      return
    }

    this.mode = 'reset-zoom'
    this.refs.imageContainer.classList.remove('zoom-to-fit')
    this.refs.zoomToFitButton.classList.remove('selected')
    this.refs.image.style.width = this.originalWidth + 'px'
    this.refs.image.style.height = this.originalHeight + 'px'
    this.refs.resetZoomButton.textContent = '100%'
    this.percentageStep = 4
  }

  // Zooms to fit the image, doesn't scale beyond actual size
  zoomToFit () {
    if (!this.loaded || this.element.offsetHeight === 0) {
      return
    }

    this.mode = 'zoom-to-fit'
    this.refs.imageContainer.classList.add('zoom-to-fit')
    this.refs.zoomToFitButton.classList.add('selected')
    this.refs.image.style.width = ''
    this.refs.image.style.height = ''
    this.refs.resetZoomButton.textContent = 'Auto'
    this.percentageStep = 4
  }

  // Adjust the size of the image by the given multiplying factor.
  //
  // factor - A {Number} to multiply against the current size.
  adjustSize (percentageStep) {
    if (!this.loaded || this.element.offsetHeight === 0) {
      return
    }

    if (this.mode === 'zoom-to-fit') {
      this.mode = 'zoom-manual'
      this.refs.imageContainer.classList.remove('zoom-to-fit')
      this.refs.zoomToFitButton.classList.remove('selected')
    } else if (this.mode === 'reset-zoom') {
      this.mode = 'zoom-manual'
    }

    const factor = this.steps[percentageStep]
    const newWidth = this.originalWidth * factor
    const newHeight = this.originalHeight * factor
    const percent = Math.max(1, Math.round((newWidth / this.originalWidth) * 100))

    // Switch to pixelated rendering when image is bigger than 200%
    if (newWidth > (this.originalWidth * 2)) {
      this.refs.image.style.imageRendering = 'pixelated'
    } else {
      this.refs.image.style.imageRendering = ''
    }

    this.refs.image.style.width = newWidth + 'px'
    this.refs.image.style.height = newHeight + 'px'
    this.refs.resetZoomButton.textContent = percent + '%'
  }

  // Changes the background color of the image view.
  //
  // color - A {String} that gets used as class name.
  changeBackground (color) {
    if (this.loaded && this.element.offsetHeight > 0 && color) {
      this.refs.imageContainer.setAttribute('background', color)
    }
  }

  scrollUp () {
    this.refs.imageContainer.scrollTop -= document.body.offsetHeight / 20
  }

  scrollDown () {
    this.refs.imageContainer.scrollTop += document.body.offsetHeight / 20
  }

  pageUp () {
    this.refs.imageContainer.scrollTop -= this.element.offsetHeight
  }

  pageDown () {
    this.refs.imageContainer.scrollTop += this.element.offsetHeight
  }

  scrollToTop () {
    this.refs.imageContainer.scrollTop = 0
  }

  scrollToBottom () {
    this.refs.imageContainer.scrollTop = this.refs.imageContainer.scrollHeight
  }
}
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs')
  , path = require('path')
  , tar = require('tar-stream')

var go = module.exports =

/**
 * Takes the given tar stream and injects a Docker file.
 *
 * @name injectDockerFile
 * @function
 * @param {ReadableStream} tarballStream of the original tarball
 * @return {ReadableStream} with the Dockerfile injected
 */
function injectDockerFile(tarballStream) {
  var pack = tar.pack()
    , extract = tar.extract();

  extract
    .on('entry', function (hdr, stream, cb) {
      inspect(hdr);
      var p = pack.entry(hdr, stream, cb)
      if (hdr.type === 'file') stream.pipe(p);
    })
    .on('finish', function () {
      pack.entry(
        { name  : 'Dockerfile'
        , mtime : new Date()
        , mode  : parseInt('644', 8)
        , uname : 'thlorenz'
        , gname : 'users'
        , uid   : 501
        , gid   : 20
        }
      , 'from dockerfile/nodejs\n');

      pack.finalize();
    });

  tarballStream.on('error', console.error).pipe(extract);
  return pack;
};

function inspect(obj, depth) {
  console.error(require('util').inspect(obj, false, depth || 5, true));
}

// Test
if (!module.parent && typeof window === 'undefined') {
  var dir = path.join(__dirname, '..', 'tmp');
  var resdir = path.join(__dirname, '..', 'result');
  var pack = tar.pack();
  var extract = tar.extract();

  var ins = fs.createReadStream(dir + '/in.tar.gz', 'utf8');

  go(ins)
    .on('error', console.error)
    .pipe(fs.createWriteStream(resdir + '/out.tar.gz', 'utf8'));
}
<commit_msg>removing root dir<commit_after>'use strict';

var fs = require('fs')
  , path = require('path')
  , tar = require('tar-stream')

function removeRootDirFrom(p) {
  var paths = p.split(path.sep);
  return path.join.apply(path, paths.slice(1));
}

var go = module.exports =

/**
 * Takes the given tar stream and injects a Docker file.
 *
 * @name injectDockerFile
 * @function
 * @param {ReadableStream} tarballStream of the original tarball
 * @param {boolean} removeRootDir if set the root dir is removed
 * @return {ReadableStream} with the Dockerfile injected
 */
function injectDockerFile(tarballStream, removeRootDir) {
  var pack = tar.pack()
    , extract = tar.extract();

  extract
    .on('entry', function (hdr, stream, cb) {
      if (removeRootDir) hdr.name = removeRootDirFrom(hdr.name);
      inspect(hdr);
      var p = pack.entry(hdr, stream, cb)
      if (hdr.type === 'file') stream.pipe(p);
    })
    .on('finish', function () {
      pack.entry(
        { name  : 'Dockerfile'
        , mtime : new Date()
        , mode  : parseInt('644', 8)
        , uname : 'thlorenz'
        , gname : 'users'
        , uid   : 501
        , gid   : 20
        }
      , 'from dockerfile/nodejs\n');

      pack.finalize();
    });

  tarballStream.on('error', console.error).pipe(extract);
  return pack;
};

function inspect(obj, depth) {
  console.error(require('util').inspect(obj, false, depth || 5, true));
}

// Test
if (!module.parent && typeof window === 'undefined') {
  var dir = path.join(__dirname, '..', 'tmp');
  var resdir = path.join(__dirname, '..', 'result');
  var pack = tar.pack();
  var extract = tar.extract();

  var ins = fs.createReadStream(dir + '/in.tar', 'utf8');

  go(ins, true)
    .on('error', console.error)
    .pipe(fs.createWriteStream(resdir + '/out.tar', 'utf8'));
}
<|endoftext|>


<commit_before>const fs = require('fs')
const mkdirp = require('mkdirp')
const path = require('path')
const nm = require('../utils/nm')
const bin = require('./installer/bin')
const dat = require('./installer/dat')
const git = require('./installer/git')
const local = require('./installer/local')
const remote = require('./installer/remote')
const registry = require('./installer/registry')
const runner = require('../run/runner')

const installer = (dep, deps, base, resolve, reject) => {
  mkdirp.sync(nm)
  mkdirp.sync(path.join(nm, '.bin'))

  const target = (base.length === 0)
    ? path.join(nm, dep)
    : path.join(nm, base.join('/'), 'node_modules', dep)
  mkdirp.sync(target)

  const pkg = deps[dep]
  var fetch

  switch (pkg.type) {
    case 'dat':
      fetch = dat(pkg, target)
      break
    case 'git':
      fetch = git(pkg, target)
      break
    case 'remote':
      fetch = remote(pkg, target)
      break
    case 'local':
      fetch = local(pkg, target)
      break
    case 'registry':
      fetch = registry(pkg, target)
      break
  }

  fetch.then(() => {
    return new Promise((resolve, reject) => {
      const args = ['install']
      const pkg = require(path.join(target, 'package.json'))
      runner(args, pkg).then(resolve).catch(reject)
    })
  }).then(() => {
    global.dependenciesCount += 1
    bin(dep, target)
    if (fs.existsSync(path.join(target, 'binding.gyp'))) {
      global.nativeBuildQueue.push(target)
    }
    if (!pkg.dependencies) return resolve()
    const tasks = Object.keys(pkg.dependencies).map((item) => {
      const list = pkg.dependencies
      var keys = [].concat(base, dep)
      if (keys.length > 1) keys.splice(-1, 0, 'node_modules')
      return new Promise((resolve, reject) => {
        installer(item, list, keys, resolve, reject)
      })
    })
    Promise.all(tasks).then(() => {
      resolve()
    })
  })
}

module.exports = (deps) => {
  return Object.keys(deps).map((dep) => {
    return new Promise((resolve, reject) => installer(dep, deps, [], resolve, reject))
  })
}
<commit_msg>fix(install): does not allow root users to run lifecycle scripts<commit_after>const fs = require('fs')
const mkdirp = require('mkdirp')
const path = require('path')
const nm = require('../utils/nm')
const bin = require('./installer/bin')
const dat = require('./installer/dat')
const git = require('./installer/git')
const local = require('./installer/local')
const remote = require('./installer/remote')
const registry = require('./installer/registry')
const runner = require('../run/runner')
const isRoot = require('is-root')

const installer = (dep, deps, base, resolve, reject) => {
  mkdirp.sync(nm)
  mkdirp.sync(path.join(nm, '.bin'))

  const target = (base.length === 0)
    ? path.join(nm, dep)
    : path.join(nm, base.join('/'), 'node_modules', dep)
  mkdirp.sync(target)

  const pkg = deps[dep]
  var fetch

  switch (pkg.type) {
    case 'dat':
      fetch = dat(pkg, target)
      break
    case 'git':
      fetch = git(pkg, target)
      break
    case 'remote':
      fetch = remote(pkg, target)
      break
    case 'local':
      fetch = local(pkg, target)
      break
    case 'registry':
      fetch = registry(pkg, target)
      break
  }

  fetch.then(() => {
    return new Promise((resolve, reject) => {
      if (isRoot()) {
        process.stdout.write(
          'dep does not allow root users to run the lifecycle of the install'
        )
        resolve()
      }
      const args = ['install']
      const pkg = require(path.join(target, 'package.json'))
      runner(args, pkg).then(resolve).catch(reject)
    })
  }).then(() => {
    global.dependenciesCount += 1
    bin(dep, target)
    if (fs.existsSync(path.join(target, 'binding.gyp'))) {
      global.nativeBuildQueue.push(target)
    }
    if (!pkg.dependencies) return resolve()
    const tasks = Object.keys(pkg.dependencies).map((item) => {
      const list = pkg.dependencies
      var keys = [].concat(base, dep)
      if (keys.length > 1) keys.splice(-1, 0, 'node_modules')
      return new Promise((resolve, reject) => {
        installer(item, list, keys, resolve, reject)
      })
    })
    Promise.all(tasks).then(() => {
      resolve()
    })
  })
}

module.exports = (deps) => {
  return Object.keys(deps).map((dep) => {
    return new Promise((resolve, reject) => installer(dep, deps, [], resolve, reject))
  })
}
<|endoftext|>


<commit_before>/* eslint max-len:0 */
const _ = require('lodash')
const chalk = require('chalk')
const fs = require('fs')
const glob = require('glob')
const noon = require('noon')

const TDIR = `${process.env.NODE_PATH}/leximaven/themes/`

/**
  * The themes module provides useful repetitive theme tasks
  * @module Themes
  */

/**
  * Loads theme
  * @public
  * @param {string} theme The name of the theme
  * @return {Object} load The style to use
  */
exports.loadTheme = (theme) => {
  let dirExists = null
  let load = null
  try {
    fs.statSync('themes')
    dirExists = true
  } catch (e) {
    if (e.code === 'ENOENT') dirExists = false
  }
  dirExists ? load = noon.load(`themes/${theme}.noon`) : load = noon.load(`${TDIR}${theme}.noon`)
  return load
}

/**
  * Gets themes for list command
  * @public
  * @return {Array} List of theme names
  */
exports.getThemes = () => {
  const list = []
  let dirExists = null
  let files = []
  try {
    fs.statSync('themes')
    dirExists = true
  } catch (e) {
    if (e.code === 'ENOENT') dirExists = false
  }
  dirExists ? files = glob.sync('themes/*.noon') : files = glob.sync(`${TDIR}*.noon`)
  _.each(files, (path) => {
    const name = path.replace(/[a-z0-9\/_\.]*themes\//, '').replace(/\.noon/, '')
    list.push(name)
  })
  return list
}

/**
  * Prints label, connector, and content
  * @public
  * @param {Object} theme The style to use
  * @param {string} direction 'down' or 'right'
  * @param {string} text The label text
  * @param {string} [content] The text the label points at
  */
exports.label = (theme, direction, text, content) => {
  const pstyle = _.get(chalk, theme.prefix.style)
  const tstyle = _.get(chalk, theme.text.style)
  const sstyle = _.get(chalk, theme.suffix.style)
  const cnstyle = _.get(chalk, theme.connector.style)
  const ctstyle = _.get(chalk, theme.content.style)
  let label = `${pstyle(theme.prefix.str)}${tstyle(text)}${sstyle(theme.suffix.str)}`
  if (direction === 'right') {
    content !== null || undefined ? label = `${label}${cnstyle(theme.connector.str)}${ctstyle(content)}` : label = `${label}`
  } else if (direction === 'down') {
    content !== null || undefined ? label = `${label}\n${cnstyle(theme.connector.str)}${ctstyle(content)}` : label = `${label}`
  } else { throw new Error("Unsupported label direction, use 'down' or 'right'.") }
  console.log(label)
}
<commit_msg>refactor(themes): add return value<commit_after>/* eslint max-len:0 */
const _ = require('lodash')
const chalk = require('chalk')
const fs = require('fs')
const glob = require('glob')
const noon = require('noon')

const TDIR = `${process.env.NODE_PATH}/leximaven/themes/`

/**
  * The themes module provides useful repetitive theme tasks
  * @module Themes
  */

/**
  * Loads theme
  * @public
  * @param {string} theme The name of the theme
  * @return {Object} load The style to use
  */
exports.loadTheme = (theme) => {
  let dirExists = null
  let load = null
  try {
    fs.statSync('themes')
    dirExists = true
  } catch (e) {
    if (e.code === 'ENOENT') dirExists = false
  }
  dirExists ? load = noon.load(`themes/${theme}.noon`) : load = noon.load(`${TDIR}${theme}.noon`)
  return load
}

/**
  * Gets themes for list command
  * @public
  * @return {Array} List of theme names
  */
exports.getThemes = () => {
  const list = []
  let dirExists = null
  let files = []
  try {
    fs.statSync('themes')
    dirExists = true
  } catch (e) {
    if (e.code === 'ENOENT') dirExists = false
  }
  dirExists ? files = glob.sync('themes/*.noon') : files = glob.sync(`${TDIR}*.noon`)
  _.each(files, (path) => {
    const name = path.replace(/[a-z0-9\/_\.]*themes\//, '').replace(/\.noon/, '')
    list.push(name)
  })
  return list
}

/**
  * Prints label, connector, and content
  * @public
  * @param {Object} theme The style to use
  * @param {string} direction 'down' or 'right'
  * @param {string} text The label text
  * @param {string} [content] The text the label points at
  * @return {string} The stylized string to log
  */
exports.label = (theme, direction, text, content) => {
  const pstyle = _.get(chalk, theme.prefix.style)
  const tstyle = _.get(chalk, theme.text.style)
  const sstyle = _.get(chalk, theme.suffix.style)
  const cnstyle = _.get(chalk, theme.connector.style)
  const ctstyle = _.get(chalk, theme.content.style)
  let label = `${pstyle(theme.prefix.str)}${tstyle(text)}${sstyle(theme.suffix.str)}`
  if (direction === 'right') {
    content !== null || undefined ? label = `${label}${cnstyle(theme.connector.str)}${ctstyle(content)}` : label = `${label}`
  } else if (direction === 'down') {
    content !== null || undefined ? label = `${label}\n${cnstyle(theme.connector.str)}${ctstyle(content)}` : label = `${label}`
  } else { throw new Error("Unsupported label direction, use 'down' or 'right'.") }
  console.log(label)
  return label
}
<|endoftext|>


<commit_before>(function (exports, requirejs, define, window, XMLHttpRequest) {
    /** ECMA SCRIPT COMPLIANT**/
    if (!String.prototype.trim) {
        String.prototype.trim = function () {
            return this.replace(/^\s+|\s+$/g, '');
        };
    }

    var underscore,
        Stage,
        document = window.document; // TODO: create workaround for node

    /***
     * marks a function to be executed asycn
     * @return {*}
     */
    Function.prototype.async = function () {
        this._async = true;
        return this;
    };

    var xamlApplication = /^(xaml!)?(.+?)(\.xml)?$/;

    var Rewrite = function (from, to) {
            this.$from = from;
            this.$to = to;
        },
        defaultNamespaceMap = {
            "http://www.w3.org/1999/xhtml": "js.html",
            "http://www.w3.org/2000/svg": "js.svg"
        },
        defaultRewriteMap = [
            new Rewrite(/^js\/html\/(a)$/, "js/html/a"),
            new Rewrite(/^js\/html\/(input)$/, "js/html/Input"),
            new Rewrite(/^js\/html\/(select)$/, "js/html/Select"),
            new Rewrite(/^js\/html\/(textarea)$/, "js/html/TextArea"),
            new Rewrite(/^js\/html\/(option)$/, "js/html/Option"),
            new Rewrite(/^js\/html\/(.+)$/, "js/html/HtmlElement"),

            new Rewrite(/^js\/svg\/svg$/, "js/svg/Svg"),
            new Rewrite(/^js\/svg\/(.+)$/, "js/svg/SvgElement")
        ];

    if (typeof JSON !== "undefined") {
        define("JSON", function () {
            return JSON;
        });
    } else {
        requirejs.config({
            paths: {
                JSON: "js/lib/json2"
            },
            shim: {
                JSON: {
                    exports: "JSON"
                }
            }
        });
    }

    requirejs.config({
        paths: {
            json: "js/plugin/json"
        }
    });

    var rAppid = {

        createApplicationContext: function (mainClass, config, callback) {

            config = config || {};

            var internalCreateApplicationContext = function (config) {

                config.xamlClasses = config.xamlClasses || [];
                config.namespaceMap = config.namespaceMap || defaultNamespaceMap;
                config.rewriteMap = config.rewriteMap || defaultRewriteMap;

                var requirejsContext = requirejs.config(config),
                    applicationContext = new ApplicationContext(requirejsContext, config);

                define("applicationContext", function () {
                    return applicationContext;
                });

                if (typeof JSON !== "undefined") {
                    define("JSON", function () {
                        return JSON;
                    });
                }

                requirejsContext(["inherit", "underscore", "js/core/Stage"], function (inherit, _, s) {
                    // we have to load inherit.js in order that inheritance is working
                    underscore = _;
                    Stage = s;

                    if (inherit && _) {

                        if (mainClass) {
                            //TODO: have a look at xamlClasses
                            var parts = xamlApplication.exec(mainClass);
                            if (parts) {
                                // mainClass is xaml
                                mainClass = "xaml!" + parts[2];
                            } else {
                                // mainClass is javascript factory
                                mainClass = mainClass.replace(/\./g, "/");
                            }

                            requirejsContext([mainClass], function (applicationFactory) {
                                applicationContext.$applicationFactory = applicationFactory;
                                callback(null, applicationContext);
                            }, function (err) {
                                callback(err);
                            });
                        } else {
                            callback(null, applicationContext);
                        }

                    } else {
                        callback("inherit or underscore missing");
                    }
                });

            };

            if (Object.prototype.toString.call(config) == '[object String]') {
                requirejs(["json!" + config], function (config) {
                    internalCreateApplicationContext(config);
                });
            } else {
                internalCreateApplicationContext(config);
            }

        },

        /***
         *
         * @param {js.core.Application} mainClass the application main class to load and start
         * @param {Element} [target=document.body] the target where the application is rendered
         * @param {Object} [parameter] an object defining the parameters passed to the Application.start method
         * @param {String|Object} [config=config.json] filename of the config file to load or configuration object
         * @param {Function} [callback] callback function in the form function (err, systemManager, application)
         */
        bootStrap: function (mainClass, target, parameter, config, callback) {

            parameter = parameter || {};

            if (typeof window !== 'undefined' && window.location && !parameter.initialHash) {
                var param = window.location.search.replace(/^\?/, '').split('&');
                for (var i = 0; i < param.length; i++) {
                    var result = /^([^=]+)=(.*)$/.exec(param[i]);
                    if (result && result[1] === 'fragment') {

                        var redirectUrl = location.protocol + '//' + location.host + location.pathname;
                        param.splice(i, 1);

                        if (param.length) {
                            redirectUrl += '?' + param.join('&');
                        }

                        redirectUrl += '#' + result[2];
                        window.location = redirectUrl;

                        return;
                    }
                }
            }

            if (!target && document && document.body) {
                // render default into document.body
                target = document.body;
            }

            config = config || "config.json";

            callback = callback || function () {
            };

            if (!document) {
                callback("Document missing");
                return;
            }

            if (!target) {
                callback("Target missing");
                return;
            }

            // flow.js is not available here, so do it in a dirty way
            rAppid.createApplicationContext(mainClass, config, function (err, applicationContext) {
                if (err) {
                    callback(err);
                } else {
                    applicationContext.createApplicationInstance(window, function (err, stage, application) {
                        if (err) {
                            callback(err);
                        } else {

                            // start the application
                            application.start(parameter, function (err) {
                                if (err) {
                                    callback(err);
                                } else {
                                    // render stage to target
                                    stage.render(target);

                                    callback(null, stage, application);
                                }
                            })
                        }
                    })
                }
            });

        },

        rewriteMapEntry: Rewrite,

        createQueryString: function (parameter) {
            var ret = [];

            for (var key in parameter) {
                if (parameter.hasOwnProperty(key)) {
                    ret.push(encodeURIComponent(key) + "=" + encodeURIComponent(parameter[key]));
                }
            }

            return ret.join("&");
        },

        ajax: function (url, options, callback) {

            var s = {
                url: url
            };

            underscore.extend(s, rAppid.ajaxSettings, options);

            if (s.data && !underscore.isString(s.data)) {
                throw "data must be a string";
            }

            s.hasContent = !/^(?:GET|HEAD)$/.test(s.type);

            if (s.queryParameter && underscore.keys(s.queryParameter).length > 0) {
                // append query parameter to url
                s.url += /\?/.test(s.url) ? "&" : "?" + this.createQueryString(s.queryParameter);
            }

            // create new xhr
            var xhr = s.xhr();
            xhr.open(s.type, s.url, s.async);

            if (s.hasContent && s.contentType !== false) {
                xhr.setRequestHeader("Content-Type", s.contentType);
                if(typeof window === "undefined"){
                    // On NodeJs the XMLHttprequest does not set Content-Length
                    // In the browser it's not allowed to set the Content-length
                    xhr.setRequestHeader("Content-Length", s.data ? s.data.length.toString() : "0");
                }
            }

            try {
                for (var header in s.headers) {
                    if (s.headers.hasOwnProperty(header)) {
                        xhr.setRequestHeader(header, s.headers[header]);
                    }
                }
            } catch(e) {
            } // FF3

            xhr.send(s.data);

            var xhrCallback = function (_, isAbort) {

                var wrappedXhr;

                if (xhrCallback && (isAbort || xhr.readyState === 4)) {
                    xhrCallback = undefined;

                    if (isAbort) {
                        // Abort it manually if needed
                        if (xhr.readyState !== 4) {
                            xhr.abort();
                        }
                    } else {
                        wrappedXhr = new rAppidXhr(xhr);
                    }

                    if (callback) {
                        callback(isAbort, wrappedXhr)
                    }
                }
            };

            if (!s.async || xhr.readyState === 4) {
                xhrCallback();
            } else {
                xhr.onreadystatechange = xhrCallback
            }

            return xhr;
        }
    };

    var rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg; // IE leaves an \r character at EOL

    var rAppidXhr = function (xhr) {
        this.xhr = xhr;
        this.status = xhr.status;
        this.$nativeResponseHeaders = xhr.getAllResponseHeaders();
        this.responses = {};

        var xml = xhr.responseXML;

        // Construct response list
        if (xml && xml.documentElement) {
            this.responses.xml = xml;
        }
        this.responses.text = xhr.responseText;

        try {
            this.statusText = xhr.statusText;
        } catch(e) {
            this.statusText = "";
        }
    };

    rAppidXhr.prototype.getResponseHeader = function (key) {
        var match;
        if (!this.$responseHeaders) {
            this.$responseHeaders = {};
            while (( match = rheaders.exec(this.$nativeResponseHeaders) )) {
                this.$responseHeaders[match[1].toLowerCase()] = match[2];
            }
        }
        return this.$responseHeaders[key.toLowerCase()];
    };

    rAppid.ajaxSettings = {
        type: "GET",
        contentType: "application/x-www-form-urlencoded",
        async: true,
        xhr: function () {
            return new XMLHttpRequest();
        },
        headers: {
        },
        data: null
    };

    var ApplicationContext = function (requirejsContext, config) {
        this.$requirejsContext = requirejsContext;
        this.$config = config;
    };

    ApplicationContext.prototype.createApplicationInstance = function (window, callback) {

        var document;

        // create instance
        var applicationFactory = this.$applicationFactory;

        if (window.document) {
            document = window.document;
        } else {
            document = window;
            window = null;
        }

        // TODO: add node support for window
        var stage = new Stage(this.$requirejsContext, this, document, window);

        this.$requirejsContext(["js/core/Application", "js/core/HeadManager", "js/core/History", "js/core/Injection"], function (Application, HeadManager, History, Injection) {
            stage.$headManager = new HeadManager(document);
            stage.$history = new History();
            var injection = stage.$injection = new Injection(null, null, stage);

            injection.addInstance(stage.$bus);
            injection.addInstance(stage.$history);
            injection.addInstance(stage.$headManager);

            var application = new applicationFactory(null, false, stage, null, null);

            if (application instanceof Application) {

                stage.$application = application;
                stage._initialize("auto");

                application._initialize("auto");

                // return rAppid instance
                if (callback) {
                    callback(null, stage, application);
                }

            } else {
                var errMessage = "mainClass isn't an instance of js.core.Application";
                if (callback) {
                    callback(errMessage);
                } else {
                    throw(errMessage);
                }
            }
        });

    };

    ApplicationContext.prototype.getFqClassName = function (namespace, className, useRewriteMap) {
        if (useRewriteMap == undefined || useRewriteMap == null) {
            useRewriteMap = true;
        }

        if (namespace && className) {
            namespace = (this.$config.namespaceMap[namespace] || namespace).replace(/\./g, '/');
            var fqClassName = [namespace, className].join("/");
        } else {
            fqClassName = (namespace || className).replace(/\./g, '/');
        }

        if (underscore.indexOf(this.$config.xamlClasses, fqClassName) !== -1) {
            fqClassName = 'xaml!' + fqClassName;
        }

        if (useRewriteMap) {
            for (var i = 0; i < this.$config.rewriteMap.length; i++) {
                var entry = this.$config.rewriteMap[i];
                if (entry instanceof rAppid.rewriteMapEntry) {
                    if (entry.$from.test(fqClassName)) {
                        return fqClassName.replace(entry.$from, entry.$to);
                    }
                }
            }
        }

        return fqClassName;
    };

    ApplicationContext.prototype.createInstance = function (fqClassName, args, className) {
        args = args || [];

        var classDefinition;

        if (fqClassName instanceof Function) {
            classDefinition = fqClassName;
            fqClassName = classDefinition.prototype.constructor.name;
        } else {
            fqClassName = fqClassName.replace(/\./g, "/");
            classDefinition = this.$requirejsContext(fqClassName);
        }

        className = className || fqClassName;

        function construct(constructor, args) {
            function F() {
                return constructor.apply(this, args);
            }

            F.prototype = constructor.prototype;
            return new F();
        }

        var ret;
        try {
            ret = construct(classDefinition, args);
            ret.className = className;
        } catch(e) {
            console.warn(["Cannot create instance of '" + fqClassName + "'", e, args]);
            throw e;
        }

        return ret;
    };

    ApplicationContext.prototype.ajax = function (url, options, callback) {

        if (!(/^http.*$/.test(url)) && this.$config.applicationUrl) {
            url = this.$config.applicationUrl + '/' + url;
        }

        rAppid.ajax(url, options, callback);
    };

    rAppid.defaultNamespaceMap = defaultNamespaceMap;
    rAppid.defaultRewriteMap = defaultRewriteMap;
    rAppid.ApplicationContext = ApplicationContext;
    rAppid.Rewrite = Rewrite;

    exports.rAppid = rAppid;

}(typeof exports !== "undefined" ? exports : window,
    typeof requirejs !== "undefined" ? requirejs : require('requirejs'),
    typeof requirejs !== "undefined" ? define : require('requirejs').define,
    typeof window !== "undefined" ? window : exports,
    typeof window !== "undefined" ? window.XMLHttpRequest : require('xmlhttprequest').XMLHttpRequest));
<commit_msg>added license to rAppid.js<commit_after>/***
 Copyright (c) 2012 Tony Findeisen, Marcus Krejpowicz

 (The MIT License)

 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.

 */
(function (exports, requirejs, define, window, XMLHttpRequest) {
    /** ECMA SCRIPT COMPLIANT**/
    if (!String.prototype.trim) {
        String.prototype.trim = function () {
            return this.replace(/^\s+|\s+$/g, '');
        };
    }

    var underscore,
        Stage,
        document = window.document; // TODO: create workaround for node

    /***
     * marks a function to be executed asycn
     * @return {*}
     */
    Function.prototype.async = function () {
        this._async = true;
        return this;
    };

    var xamlApplication = /^(xaml!)?(.+?)(\.xml)?$/;

    var Rewrite = function (from, to) {
            this.$from = from;
            this.$to = to;
        },
        defaultNamespaceMap = {
            "http://www.w3.org/1999/xhtml": "js.html",
            "http://www.w3.org/2000/svg": "js.svg"
        },
        defaultRewriteMap = [
            new Rewrite(/^js\/html\/(a)$/, "js/html/a"),
            new Rewrite(/^js\/html\/(input)$/, "js/html/Input"),
            new Rewrite(/^js\/html\/(select)$/, "js/html/Select"),
            new Rewrite(/^js\/html\/(textarea)$/, "js/html/TextArea"),
            new Rewrite(/^js\/html\/(option)$/, "js/html/Option"),
            new Rewrite(/^js\/html\/(.+)$/, "js/html/HtmlElement"),

            new Rewrite(/^js\/svg\/svg$/, "js/svg/Svg"),
            new Rewrite(/^js\/svg\/(.+)$/, "js/svg/SvgElement")
        ];

    if (typeof JSON !== "undefined") {
        define("JSON", function () {
            return JSON;
        });
    } else {
        requirejs.config({
            paths: {
                JSON: "js/lib/json2"
            },
            shim: {
                JSON: {
                    exports: "JSON"
                }
            }
        });
    }

    requirejs.config({
        paths: {
            json: "js/plugin/json"
        }
    });

    var rAppid = {

        createApplicationContext: function (mainClass, config, callback) {

            config = config || {};

            var internalCreateApplicationContext = function (config) {

                config.xamlClasses = config.xamlClasses || [];
                config.namespaceMap = config.namespaceMap || defaultNamespaceMap;
                config.rewriteMap = config.rewriteMap || defaultRewriteMap;

                var requirejsContext = requirejs.config(config),
                    applicationContext = new ApplicationContext(requirejsContext, config);

                define("applicationContext", function () {
                    return applicationContext;
                });

                if (typeof JSON !== "undefined") {
                    define("JSON", function () {
                        return JSON;
                    });
                }

                requirejsContext(["inherit", "underscore", "js/core/Stage"], function (inherit, _, s) {
                    // we have to load inherit.js in order that inheritance is working
                    underscore = _;
                    Stage = s;

                    if (inherit && _) {

                        if (mainClass) {
                            //TODO: have a look at xamlClasses
                            var parts = xamlApplication.exec(mainClass);
                            if (parts) {
                                // mainClass is xaml
                                mainClass = "xaml!" + parts[2];
                            } else {
                                // mainClass is javascript factory
                                mainClass = mainClass.replace(/\./g, "/");
                            }

                            requirejsContext([mainClass], function (applicationFactory) {
                                applicationContext.$applicationFactory = applicationFactory;
                                callback(null, applicationContext);
                            }, function (err) {
                                callback(err);
                            });
                        } else {
                            callback(null, applicationContext);
                        }

                    } else {
                        callback("inherit or underscore missing");
                    }
                });

            };

            if (Object.prototype.toString.call(config) == '[object String]') {
                requirejs(["json!" + config], function (config) {
                    internalCreateApplicationContext(config);
                });
            } else {
                internalCreateApplicationContext(config);
            }

        },

        /***
         *
         * @param {js.core.Application} mainClass the application main class to load and start
         * @param {Element} [target=document.body] the target where the application is rendered
         * @param {Object} [parameter] an object defining the parameters passed to the Application.start method
         * @param {String|Object} [config=config.json] filename of the config file to load or configuration object
         * @param {Function} [callback] callback function in the form function (err, systemManager, application)
         */
        bootStrap: function (mainClass, target, parameter, config, callback) {

            parameter = parameter || {};

            if (typeof window !== 'undefined' && window.location && !parameter.initialHash) {
                var param = window.location.search.replace(/^\?/, '').split('&');
                for (var i = 0; i < param.length; i++) {
                    var result = /^([^=]+)=(.*)$/.exec(param[i]);
                    if (result && result[1] === 'fragment') {

                        var redirectUrl = location.protocol + '//' + location.host + location.pathname;
                        param.splice(i, 1);

                        if (param.length) {
                            redirectUrl += '?' + param.join('&');
                        }

                        redirectUrl += '#' + result[2];
                        window.location = redirectUrl;

                        return;
                    }
                }
            }

            if (!target && document && document.body) {
                // render default into document.body
                target = document.body;
            }

            config = config || "config.json";

            callback = callback || function () {
            };

            if (!document) {
                callback("Document missing");
                return;
            }

            if (!target) {
                callback("Target missing");
                return;
            }

            // flow.js is not available here, so do it in a dirty way
            rAppid.createApplicationContext(mainClass, config, function (err, applicationContext) {
                if (err) {
                    callback(err);
                } else {
                    applicationContext.createApplicationInstance(window, function (err, stage, application) {
                        if (err) {
                            callback(err);
                        } else {

                            // start the application
                            application.start(parameter, function (err) {
                                if (err) {
                                    callback(err);
                                } else {
                                    // render stage to target
                                    stage.render(target);

                                    callback(null, stage, application);
                                }
                            })
                        }
                    })
                }
            });

        },

        rewriteMapEntry: Rewrite,

        createQueryString: function (parameter) {
            var ret = [];

            for (var key in parameter) {
                if (parameter.hasOwnProperty(key)) {
                    ret.push(encodeURIComponent(key) + "=" + encodeURIComponent(parameter[key]));
                }
            }

            return ret.join("&");
        },

        ajax: function (url, options, callback) {

            var s = {
                url: url
            };

            underscore.extend(s, rAppid.ajaxSettings, options);

            if (s.data && !underscore.isString(s.data)) {
                throw "data must be a string";
            }

            s.hasContent = !/^(?:GET|HEAD)$/.test(s.type);

            if (s.queryParameter && underscore.keys(s.queryParameter).length > 0) {
                // append query parameter to url
                s.url += /\?/.test(s.url) ? "&" : "?" + this.createQueryString(s.queryParameter);
            }

            // create new xhr
            var xhr = s.xhr();
            xhr.open(s.type, s.url, s.async);

            if (s.hasContent && s.contentType !== false) {
                xhr.setRequestHeader("Content-Type", s.contentType);
                if(typeof window === "undefined"){
                    // On NodeJs the XMLHttprequest does not set Content-Length
                    // In the browser it's not allowed to set the Content-length
                    xhr.setRequestHeader("Content-Length", s.data ? s.data.length.toString() : "0");
                }
            }

            try {
                for (var header in s.headers) {
                    if (s.headers.hasOwnProperty(header)) {
                        xhr.setRequestHeader(header, s.headers[header]);
                    }
                }
            } catch(e) {
            } // FF3

            xhr.send(s.data);

            var xhrCallback = function (_, isAbort) {

                var wrappedXhr;

                if (xhrCallback && (isAbort || xhr.readyState === 4)) {
                    xhrCallback = undefined;

                    if (isAbort) {
                        // Abort it manually if needed
                        if (xhr.readyState !== 4) {
                            xhr.abort();
                        }
                    } else {
                        wrappedXhr = new rAppidXhr(xhr);
                    }

                    if (callback) {
                        callback(isAbort, wrappedXhr)
                    }
                }
            };

            if (!s.async || xhr.readyState === 4) {
                xhrCallback();
            } else {
                xhr.onreadystatechange = xhrCallback
            }

            return xhr;
        }
    };

    var rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg; // IE leaves an \r character at EOL

    var rAppidXhr = function (xhr) {
        this.xhr = xhr;
        this.status = xhr.status;
        this.$nativeResponseHeaders = xhr.getAllResponseHeaders();
        this.responses = {};

        var xml = xhr.responseXML;

        // Construct response list
        if (xml && xml.documentElement) {
            this.responses.xml = xml;
        }
        this.responses.text = xhr.responseText;

        try {
            this.statusText = xhr.statusText;
        } catch(e) {
            this.statusText = "";
        }
    };

    rAppidXhr.prototype.getResponseHeader = function (key) {
        var match;
        if (!this.$responseHeaders) {
            this.$responseHeaders = {};
            while (( match = rheaders.exec(this.$nativeResponseHeaders) )) {
                this.$responseHeaders[match[1].toLowerCase()] = match[2];
            }
        }
        return this.$responseHeaders[key.toLowerCase()];
    };

    rAppid.ajaxSettings = {
        type: "GET",
        contentType: "application/x-www-form-urlencoded",
        async: true,
        xhr: function () {
            return new XMLHttpRequest();
        },
        headers: {
        },
        data: null
    };

    var ApplicationContext = function (requirejsContext, config) {
        this.$requirejsContext = requirejsContext;
        this.$config = config;
    };

    ApplicationContext.prototype.createApplicationInstance = function (window, callback) {

        var document;

        // create instance
        var applicationFactory = this.$applicationFactory;

        if (window.document) {
            document = window.document;
        } else {
            document = window;
            window = null;
        }

        // TODO: add node support for window
        var stage = new Stage(this.$requirejsContext, this, document, window);

        this.$requirejsContext(["js/core/Application", "js/core/HeadManager", "js/core/History", "js/core/Injection"], function (Application, HeadManager, History, Injection) {
            stage.$headManager = new HeadManager(document);
            stage.$history = new History();
            var injection = stage.$injection = new Injection(null, null, stage);

            injection.addInstance(stage.$bus);
            injection.addInstance(stage.$history);
            injection.addInstance(stage.$headManager);

            var application = new applicationFactory(null, false, stage, null, null);

            if (application instanceof Application) {

                stage.$application = application;
                stage._initialize("auto");

                application._initialize("auto");

                // return rAppid instance
                if (callback) {
                    callback(null, stage, application);
                }

            } else {
                var errMessage = "mainClass isn't an instance of js.core.Application";
                if (callback) {
                    callback(errMessage);
                } else {
                    throw(errMessage);
                }
            }
        });

    };

    ApplicationContext.prototype.getFqClassName = function (namespace, className, useRewriteMap) {
        if (useRewriteMap == undefined || useRewriteMap == null) {
            useRewriteMap = true;
        }

        if (namespace && className) {
            namespace = (this.$config.namespaceMap[namespace] || namespace).replace(/\./g, '/');
            var fqClassName = [namespace, className].join("/");
        } else {
            fqClassName = (namespace || className).replace(/\./g, '/');
        }

        if (underscore.indexOf(this.$config.xamlClasses, fqClassName) !== -1) {
            fqClassName = 'xaml!' + fqClassName;
        }

        if (useRewriteMap) {
            for (var i = 0; i < this.$config.rewriteMap.length; i++) {
                var entry = this.$config.rewriteMap[i];
                if (entry instanceof rAppid.rewriteMapEntry) {
                    if (entry.$from.test(fqClassName)) {
                        return fqClassName.replace(entry.$from, entry.$to);
                    }
                }
            }
        }

        return fqClassName;
    };

    ApplicationContext.prototype.createInstance = function (fqClassName, args, className) {
        args = args || [];

        var classDefinition;

        if (fqClassName instanceof Function) {
            classDefinition = fqClassName;
            fqClassName = classDefinition.prototype.constructor.name;
        } else {
            fqClassName = fqClassName.replace(/\./g, "/");
            classDefinition = this.$requirejsContext(fqClassName);
        }

        className = className || fqClassName;

        function construct(constructor, args) {
            function F() {
                return constructor.apply(this, args);
            }

            F.prototype = constructor.prototype;
            return new F();
        }

        var ret;
        try {
            ret = construct(classDefinition, args);
            ret.className = className;
        } catch(e) {
            console.warn(["Cannot create instance of '" + fqClassName + "'", e, args]);
            throw e;
        }

        return ret;
    };

    ApplicationContext.prototype.ajax = function (url, options, callback) {

        if (!(/^http.*$/.test(url)) && this.$config.applicationUrl) {
            url = this.$config.applicationUrl + '/' + url;
        }

        rAppid.ajax(url, options, callback);
    };

    rAppid.defaultNamespaceMap = defaultNamespaceMap;
    rAppid.defaultRewriteMap = defaultRewriteMap;
    rAppid.ApplicationContext = ApplicationContext;
    rAppid.Rewrite = Rewrite;

    exports.rAppid = rAppid;

}(typeof exports !== "undefined" ? exports : window,
    typeof requirejs !== "undefined" ? requirejs : require('requirejs'),
    typeof requirejs !== "undefined" ? define : require('requirejs').define,
    typeof window !== "undefined" ? window : exports,
    typeof window !== "undefined" ? window.XMLHttpRequest : require('xmlhttprequest').XMLHttpRequest));
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var check = require('check-types');
var parseCode = require('./parser').parseCode;
var parseUnitTestCode = require('./parserUnitTest').parseUnitTestCode;

var apiComments = null;

module.exports = function (apiJson, htmlFilename) {
	check.verifyArray(apiJson, 'missing api array');
	check.verifyString(htmlFilename, 'missing output filename');

	console.log('generating html to', htmlFilename);
	var title = 'Sample API';
	var o = '<!DOCTYPE HTML>\n';
	o += '\n\n';
	o += '\t<title>Api</title>\n';
	var css = fileContents('./api.css');
	check.verifyString(css, 'could not get css');
	o += '\t\n';
	o += '\n';
	o += '\n';

	var script = fileContents('./toggle.js');
	check.verifyString(script, 'could not get toggle script');
	o += '\n';
	o += '\n';
	o += '\n';
	o += '
' + title + ' by xplain
\n';
	o += '\t
\n';

	var methodDocs = [];
	apiComments = apiJson;
	apiComments.forEach(function (apiComment) {
		console.log('checking comment', apiComment);
		if (!isMethod(apiComment)) {
			return;
		}
		console.log('found method comment');
		var info = methodDiv(apiComment);
		check.verifyString(info.name, 'did not get method name string');
		check.verifyString(info.docs, 'did not get method docs string');
		methodDocs.push(info);
	});

	var indexStr = '';
	var docsStr = '';
	methodDocs.forEach(function (info) {
		indexStr += info.name + '\n';
		docsStr += info.docs + '\n';
	});

	o += '\t\t
\n' + indexStr + '\t\t
\n';
	o += '\t\t
\n' + docsStr + '\t\t
\n';
	o += '\t
\n'; // content
	o += '\n';
	o += '\n';
	fs.writeFileSync(htmlFilename, o, 'utf-8');
};

function fileContents(name) {
	check.verifyString(name, 'missing file name');
	var cssFilename = path.join(__dirname, name);
	var cssText = fs.readFileSync(cssFilename, 'utf8');
	return cssText;
}

function isMethod(apiComment) {
	if (!Array.isArray(apiComment.tags)) {
		return false;
	}
	return apiComment.tags.some(function (tag) {
		return tag.type === 'method';
	});
}

function isExampleFor(apiComment, name) {
	if (!Array.isArray(apiComment.tags)) {
		return false;
	}
	return apiComment.tags.some(function (tag) {
		return (tag.type === 'exampleFor' || tag.type === 'example')
			&& tag.string === name;
	});
}

function isSampleFor(apiComment, name) {
	if (!Array.isArray(apiComment.tags)) {
		return false;
	}
	return apiComment.tags.some(function (tag) {
		return (tag.type === 'sampleFor' || tag.type === 'sample')
			&& tag.string === name;
	});
}

function examplesFor(name) {
	check.verifyString(name, 'missing name');
	check.verifyArray(apiComments, 'missing api comments');
	var apiExamples = apiComments.filter(function (apiComment) {
		return isExampleFor(apiComment, name);
	});
	console.log('have', apiExamples.length, 'examples for', name);
	// console.log(apiExamples);

	var examples = apiExamples.map(function (example) {
		console.log('example', example);
		return exampleDiv(name, example);
	});
	// console.log('examples', examples);
	// return examples.join('\n');
	return examples;
}

function samplesFor(name) {
	check.verifyString(name, 'missing name');
	check.verifyArray(apiComments, 'missing api comments');
	var apiSamples = apiComments.filter(function (apiComment) {
		return isSampleFor(apiComment, name);
	});
	console.log('have', apiSamples.length, 'samples for', name);
	console.log(apiSamples);
	var samples = apiSamples.map(sampleDiv);
	console.log('samples', samples);
	return samples.join('\n');
}

var exampleDivId = 0;
function exampleDiv(name, apiExample) {
	check.verifyString(name, 'missing method name');
	check.verifyObject(apiExample, 'missing example code string');

	var id = name + '_example_' + ++exampleDivId + '_toggle';
	var toggle = '<input class="toggle" type="button" value="example ' + exampleDivId + '" id="' + id + '">\n';
	var o = '
\n';
	o += '
\n' + apiExample.code + '\n
\n';
	o += '
\n';
	return {
		toggle: toggle,
		code: o
	};
}

function sampleToCommentLike(testCode) {
	check.verifyString(testCode, 'missing test code');
	var parsed = parseCode(testCode);
	check.verifyObject(parsed, 'could not parse\n' + testCode);
	return parsed;
}

var sampleDivId = 1;
function sampleDiv(apiExample) {
	var o = '
\n';
	var code = apiExample.code;
	check.verifyString(code, 'missing code for sample');
	var parsed = sampleToCommentLike(code);
	check.verifyObject(parsed, 'did not get sample from', code);
	check.verifyString(parsed.name, 'there is no name for', code);
	check.verifyString(parsed.code, 'there is no code for', code);
	var humanForm = parseUnitTestCode(parsed.code);
	console.log('human form', humanForm);
	if (!check.isString(humanForm)) {
		console.log('could not convert', parseCode, 'to human form');
		humanForm = parsed.code;
	}
	check.verifyString(humanForm, 'could not convert to human form', parsed.code);
	o += '' + parsed.name + '\n';
	o += '
\n';
	o += ''
	o += humanForm;
	o += '\n';
	o += '
\n';
	o += '
\n';
	return o;
}

function methodDiv(apiComment) {
	check.verifyObject(apiComment, 'missing api comment object');
	console.assert(apiComment.ctx, 'missing ctx property');
	console.assert(apiComment.ctx.type === 'function', 'ctx is not function');
	check.verifyString(apiComment.ctx.name, 'missing function name');
	var name = apiComment.ctx.name;

	var o = '
\n';
	o += '
' + name + '
\n';
	o += apiComment.description.summary + '\n';

	var samples = samplesFor(name);
	if (samples) {
		o += samples + '\n';
	}

	var toggles = '';
	var examplesText = '';

	var examples = examplesFor(name);
	check.verifyArray(examples, 'could not get examples tags');
	examples.forEach(function (example) {
		toggles += example.toggle + '\n';
		examplesText += example.code + '\n';
	});

	var id = name + '_code_toggle';
	var toggle = '<input class="toggle" type="button" value="code" id="' + id + '">\n';
	toggles += toggle;

	o += toggles + '\n';
	o += examplesText + '\n';
	o += '
\n';
	o += '
\n' + apiComment.code + '
\n';
	o += '
\n';

	o += '
\n';

	var nameDiv = '
'
		+ name + '
';
	return {
		name: nameDiv,
		docs: o
	};
}<commit_msg>google syntax highlighter used for code samples<commit_after>var fs = require('fs');
var path = require('path');
var check = require('check-types');
var parseCode = require('./parser').parseCode;
var parseUnitTestCode = require('./parserUnitTest').parseUnitTestCode;

var apiComments = null;

module.exports = function (apiJson, htmlFilename) {
	check.verifyArray(apiJson, 'missing api array');
	check.verifyString(htmlFilename, 'missing output filename');

	console.log('generating html to', htmlFilename);
	var title = 'Sample API';
	var o = '<!DOCTYPE HTML>\n';
	o += '\n\n';
	o += '\t<title>Api</title>\n';
	var css = fileContents('./api.css');
	check.verifyString(css, 'could not get css');
	o += '\t\n';
	o += '\n';
	o += '\n';

	var script = fileContents('./toggle.js');
	check.verifyString(script, 'could not get toggle script');
	o += '\n';
	o += '\n';
	o += '\n';
	o += '
' + title + ' by xplain
\n';
	o += '\t
\n';

	var methodDocs = [];
	apiComments = apiJson;
	apiComments.forEach(function (apiComment) {
		console.log('checking comment', apiComment);
		if (!isMethod(apiComment)) {
			return;
		}
		console.log('found method comment');
		var info = methodDiv(apiComment);
		check.verifyString(info.name, 'did not get method name string');
		check.verifyString(info.docs, 'did not get method docs string');
		methodDocs.push(info);
	});

	var indexStr = '';
	var docsStr = '';
	methodDocs.forEach(function (info) {
		indexStr += info.name + '\n';
		docsStr += info.docs + '\n';
	});

	o += '\t\t
\n' + indexStr + '\t\t
\n';
	o += '\t\t
\n' + docsStr + '\t\t
\n';
	o += '\t
\n'; // content
	o += '\n';
	o += '\n';
	fs.writeFileSync(htmlFilename, o, 'utf-8');
};

function fileContents(name) {
	check.verifyString(name, 'missing file name');
	var cssFilename = path.join(__dirname, name);
	var cssText = fs.readFileSync(cssFilename, 'utf8');
	return cssText;
}

function isMethod(apiComment) {
	if (!Array.isArray(apiComment.tags)) {
		return false;
	}
	return apiComment.tags.some(function (tag) {
		return tag.type === 'method';
	});
}

function isExampleFor(apiComment, name) {
	if (!Array.isArray(apiComment.tags)) {
		return false;
	}
	return apiComment.tags.some(function (tag) {
		return (tag.type === 'exampleFor' || tag.type === 'example')
			&& tag.string === name;
	});
}

function isSampleFor(apiComment, name) {
	if (!Array.isArray(apiComment.tags)) {
		return false;
	}
	return apiComment.tags.some(function (tag) {
		return (tag.type === 'sampleFor' || tag.type === 'sample')
			&& tag.string === name;
	});
}

function examplesFor(name) {
	check.verifyString(name, 'missing name');
	check.verifyArray(apiComments, 'missing api comments');
	var apiExamples = apiComments.filter(function (apiComment) {
		return isExampleFor(apiComment, name);
	});
	console.log('have', apiExamples.length, 'examples for', name);
	// console.log(apiExamples);

	var examples = apiExamples.map(function (example) {
		console.log('example', example);
		return exampleDiv(name, example);
	});
	// console.log('examples', examples);
	// return examples.join('\n');
	return examples;
}

function samplesFor(name) {
	check.verifyString(name, 'missing name');
	check.verifyArray(apiComments, 'missing api comments');
	var apiSamples = apiComments.filter(function (apiComment) {
		return isSampleFor(apiComment, name);
	});
	console.log('have', apiSamples.length, 'samples for', name);
	console.log(apiSamples);
	var samples = apiSamples.map(sampleDiv);
	console.log('samples', samples);
	return samples.join('\n');
}

var exampleDivId = 0;
function exampleDiv(name, apiExample) {
	check.verifyString(name, 'missing method name');
	check.verifyObject(apiExample, 'missing example code string');

	var id = name + '_example_' + ++exampleDivId + '_toggle';
	var toggle = '<input class="toggle" type="button" value="example ' + exampleDivId + '" id="' + id + '">\n';
	var o = '
\n';
	o += '
\n' + apiExample.code + '\n
\n';
	o += '
\n';
	return {
		toggle: toggle,
		code: o
	};
}

function sampleToCommentLike(testCode) {
	check.verifyString(testCode, 'missing test code');
	var parsed = parseCode(testCode);
	check.verifyObject(parsed, 'could not parse\n' + testCode);
	return parsed;
}

var sampleDivId = 1;
function sampleDiv(apiExample) {
	var o = '
\n';
	var code = apiExample.code;
	check.verifyString(code, 'missing code for sample');
	var parsed = sampleToCommentLike(code);
	check.verifyObject(parsed, 'did not get sample from', code);
	check.verifyString(parsed.name, 'there is no name for', code);
	check.verifyString(parsed.code, 'there is no code for', code);
	var humanForm = parseUnitTestCode(parsed.code);
	console.log('human form', humanForm);
	if (!check.isString(humanForm)) {
		console.log('could not convert', parseCode, 'to human form');
		humanForm = parsed.code;
	}
	check.verifyString(humanForm, 'could not convert to human form', parsed.code);
	o += '' + parsed.name + '\n';
	o += '
\n';
	o += ''
	o += humanForm;
	o += '\n';
	o += '
\n';
	o += '
\n';
	return o;
}

function methodDiv(apiComment) {
	check.verifyObject(apiComment, 'missing api comment object');
	console.assert(apiComment.ctx, 'missing ctx property');
	console.assert(apiComment.ctx.type === 'function', 'ctx is not function');
	check.verifyString(apiComment.ctx.name, 'missing function name');
	var name = apiComment.ctx.name;

	var o = '
\n';
	o += '
' + name + '
\n';
	o += apiComment.description.summary + '\n';

	var samples = samplesFor(name);
	if (samples) {
		o += samples + '\n';
	}

	var toggles = '';
	var examplesText = '';

	var examples = examplesFor(name);
	check.verifyArray(examples, 'could not get examples tags');
	examples.forEach(function (example) {
		toggles += example.toggle + '\n';
		examplesText += example.code + '\n';
	});

	var id = name + '_code_toggle';
	var toggle = '<input class="toggle" type="button" value="code" id="' + id + '">\n';
	toggles += toggle;

	o += toggles + '\n';
	o += examplesText + '\n';
	o += '
\n';
	o += '
\n' + apiComment.code + '
\n';
	o += '
\n';

	o += '
\n';

	var nameDiv = '
'
		+ name + '
';
	return {
		name: nameDiv,
		docs: o
	};
}<|endoftext|>