<commit_before>const _ = require('lodash');
const moment = require('moment');
const Promise = require('bluebird');
const debug = require('debug')('routes:semantics');
const nconf = require('nconf');

const mongo = require('../lib/mongo');
const params = require('../lib/params');
const semantic = require('../lib/semantic');
const various = require('../lib/various');

const LanguageError = {
    error: true,
    message: 'missing language',
    supported: semantic.langMap,
    reminder: 'the list of supported language comes from a mongodb.distinct call, should be updated'
};

function validLanguage(propl) {
    return (_.size(propl) == 2 && !_.isUndefined(_.get(semantic.langMap, propl)));
}

function labels(req) {
    const { amount, skip } = params.optionParsing(req.params.paging, 100);
    debug("labels request (lang: %s), amount %d skip %d",
        req.params.lang, amount, skip);

    if(!validLanguage(req.params.lang))
        return { json: LanguageError };

    return mongo
        .readLimit(nconf.get('schema').labels, { lang: req.params.lang }, { when: -1 }, amount, skip)
        .then(function(data) {
            debug("retrived %d objects, with amount %d skip %d", _.size(data), amount, skip);
            return { json: data };
        })
        .catch(function(e) {
            debug("data (error): %s", e);
            return { 'text': `error: ${e}` };
        });
};

function semantics(req) {
    const { amount, skip } = params.optionParsing(req.params.paging, 100);
    debug("semantic request (lang: %s), amount %d skip %d",
        req.params.lang, amount, skip);

    if(!validLanguage(req.params.lang))
        return { json: LanguageError };

    return mongo
        .readLimit(nconf.get('schema').semantics, { lang: req.params.lang }, { when: -1 }, amount, skip)
        .then(function(data) {
            debug("retrived %d objects, with amount %d skip %d", _.size(data), amount, skip);
            return { json: data };
        })
        .catch(function(e) {
            debug("data (error): %s", e);
            return { 'text': `error: ${e}` };
        });
};

function redactEnriched(enrich) {
    _.unset(enrich, '_id');
    let s = _.first(enrich.summary);
    _.unset(s, '_id');
    _.unset(s, 'id');
    _.unset(s, 'user');
    _.unset(s, 'timeline');
    _.unset(s, 'impressionOrder');
    _.unset(s, 'impressionTime');
    enrich.summary = s;
    // XXX maybe can be redacted the condition of the ❌ below
    return enrich;
}

function enrich(req) {
    const DEFAULTAMOUNT = 13;
    const backintime = moment().subtract(2, 'd').toISOString();
    const { amount, skip } = params.optionParsing(req.params.paging, DEFAULTAMOUNT);
    debug("enrich request (lang: %s), amount %d skip %d",
        req.params.lang, amount, skip);

    if(!validLanguage(req.params.lang))
        return { json: LanguageError };

    return mongo
        .aggregate(nconf.get('schema').labels, [
            { $sort: { when: -1 }},
            { $match: { lang: req.params.lang, when: { "$lt": new Date(backintime) }} },
            { $skip: skip },
            { $limit: amount },
            { $lookup: { from: 'summary', localField: 'semanticId', foreignField: 'semanticId', as: 'summary' }}
        ])
        .map(redactEnriched)
        .then(function(enriched) {
            debug("return enrich, %d objects (%j)", _.size(enriched), _.map(enriched, function(e) {
                if(!e.summary || !e.summary.source || !e.summary.nature)
                    return "❌";
                return [ e.summary.source, e.summary.nature ];
            }));
            return { json: enriched };
        });
};

function noogle(req) {
    const DEFAULTAMOUNT = 13;
    const { amount, skip } = params.optionParsing(req.params.paging, DEFAULTAMOUNT);
    debug("noogle request (lang: %s, label: %s), amount %d skip %d",
        req.params.lang, req.params.label, amount, skip);

    if(!validLanguage(req.params.lang))
        return { json: LanguageError };

    return mongo
        .aggregate(nconf.get('schema').semantics, [
            { $sort: { when: -1 }},
            { $match: { lang: req.params.lang, label: req.params.label }},
            { $group: { _id: "$semanticId" }},
            { $skip: skip },
            { $limit: amount },
            { $lookup: { from: 'summary', localField: '_id', foreignField: 'semanticId', as: 'summary' }},
            { $lookup: { from: 'labels', localField: '_id', foreignField: 'semanticId', as: 'labels' }}
        ])
        .map(function(dirty) {
            let base = _.first(dirty.labels);
            base.summary = dirty.summary;
            base.when = moment(base.when);
            return base;
        })
        .map(redactEnriched)
        .then(function(results) {
            /*
            debug("return noogle, %d objects (%j)", _.size(results), _.map(results, function(e) {
                if(!e.summary || !e.summary.source || !e.summary.nature)
                    return "❌";
                return [ e.summary.source, e.summary.nature ];
            }));
            */
            const ordered = _.orderBy(results, {when: -1 });
            return { json: results };
        });
};

function loud(req) {
    const MAXENTRIES = 2000;
    const DEFAULTAMOUNT = 13;
    const backintime = moment().subtract(2, 'd').toISOString();
    const { amount, skip } = params.optionParsing(req.params.paging, DEFAULTAMOUNT);
    debug("loud request (lang: %s), amount %d skip %d",
        req.params.lang, amount, skip);

    if(!validLanguage(req.params.lang))
        return { json: LanguageError };

    return loudKeywordsPipeline(MAXENTRIES, backintime, amount, skip, req.params.lang)
        .then(function(loudness) {
            debug("return loudness: %j", _.map(loudness, 'label'));
            return { json: loudness };
        });

};

function loudKeywordsPipeline(maxentries, backintime, amount, skip, lang) {
    return mongo
        .aggregate(nconf.get('schema').semantics, [
            { $match: { lang: lang, when: { "$gt": new Date(backintime) }} },
            { $limit: maxentries },
            { $group: { _id: '$title', wp: { $first: '$wp'}, count: { $sum: 1 }}},
            { $sort: { "count": -1 }},
            { $skip: skip },
            { $limit: amount },
            { $project: { "label": "$_id", _id: false, wp: true, count: true }}
        ]);
}

/* This is the cache block used by langinfo */
const cache = _.reduce(semantic.langMap, function(memo, langName, l) {
    _.set(memo, l, {
        langName,
        content: null,
        computedAt: null,
        next: null,
    });
    return memo;
}, {} );

/* This is part of the langinfo feature */
function formatReturn(lang, updated) {
    if(updated) {
        cache[lang].content = updated.content;
        cache[lang].computedAt = updated.computedAt;
        cache[lang].next = updated.next
    }
    return {
        json: {
            content: cache[lang].content,
            computedAt: cache[lang].computedAt.toISOString(),
            next: cache[lang].next.toISOString(),
        }
    };
};

function langinfo(req) {
    /* this API returns an complete information on a language population, with number of
     * active contributors in the last 48 hours and total keyword seen in the last 48 hours,
     * this API do not support paging and is meant to be cached */
    const MAXENTRIES = 60000;
    const DEFAULTAMOUNT = 10;
    const hoursNumber = 48;
    const backintime = moment().subtract(hoursNumber, 'h').toISOString();
    const amount = 13;
    const skip = 0;
    const lang = req.params.lang;
    const cacheMinutes = 60 * 12;

    if(!validLanguage(lang))
        return { json: LanguageError };

    if(cache[lang].next && moment().isBefore(cache[lang].next) && cache[lang].content) {
        debug("langInfo %s, using cached version", lang);
        return formatReturn(lang);
    }

    debug("langInfo %s, retrieving from DB", lang);
    return Promise.all([
        loudKeywordsPipeline(MAXENTRIES, backintime, amount, skip, lang),
        mongo.aggregate(nconf.get('schema').semantics, [
            { $sort: { when: -1 }},
            { $match: { lang: req.params.lang, when: { "$gt": new Date(backintime) } }},
            { $limit: MAXENTRIES },
            { $group: { _id: "$label" }},
            { $group: { _id: null, amount: { "$sum": 1 } }},
        ]).then(function(o) { return (o && o[0] && o[0].amount) ? o[0].amount : 0 }),
        mongo.aggregate(nconf.get('schema').labels, [
            { $sort: { when: -1 }},
            { $match: { lang: lang, when: { "$gt": new Date(backintime) } }},
            { $limit: MAXENTRIES },
            { $lookup: { from: 'summary', localField: 'semanticId', foreignField: 'semanticId', as: 'summary' }},
            { $group: { _id: "dummy", profiles: { $addToSet: "$summary.user"} }}
        ]).then(function(usermess) {
            // remind/TODO grouped by size and anonymized, this can be a nice stats
            // _.flatten(usermess[0].profiles)
            if(!(usermess && usermess[0] && usermess[0].profiles))
                return 0;
            return _.size(_.uniq(_.flatten(usermess[0].profiles)))
        })
    ])
    .then(function(results) {
        let retval = {
            consideredHoursWindow: hoursNumber,
            language: req.params.lang,
            most: _.map(results[0], 'label'),
            labelsCount: results[1],
            contributors: results[2],
        };
        return formatReturn(lang, {
            content: retval,
            computedAt: moment(),
            next: moment().add(cacheMinutes, 'minutes')
        });
    });
}

function languages(req) {
    return various
        .loadJSONfile('rss/keywords/available.json')
        .then(function(available) {
            debug("Loaded %d available on %d potential",
                _.size(available), _.size(semantic.langMap));
            return {
                json: {
                    available,
                    potential: semantic.langMap
                }
            };
        });
};

function keywords(req) {
    const lc = req.params.lang;
    debug("keywords request for %s", lc);
    if(!validLanguage(lc))
        return { json: LanguageError };
    return various
        .loadJSONfile(`rss/keywords/${lc}.json`)
        .then(function(kwds) {
            debug("%d keywords returned as part of %s",
                _.size(kwds), lc);
            return { json: kwds };
        });
};

module.exports = {
    labels,
    semantics,
    enrich,
    loud,
    noogle,
    langinfo,
    languages,
    keywords
};
<commit_msg>fixed a bug in noogle<commit_after>const _ = require('lodash');
const moment = require('moment');
const Promise = require('bluebird');
const debug = require('debug')('routes:semantics');
const nconf = require('nconf');

const mongo = require('../lib/mongo');
const params = require('../lib/params');
const semantic = require('../lib/semantic');
const various = require('../lib/various');

const LanguageError = {
    error: true,
    message: 'missing language',
    supported: semantic.langMap,
    reminder: 'the list of supported language comes from a mongodb.distinct call, should be updated'
};

function validLanguage(propl) {
    return (_.size(propl) == 2 && !_.isUndefined(_.get(semantic.langMap, propl)));
}

function labels(req) {
    const { amount, skip } = params.optionParsing(req.params.paging, 100);
    debug("labels request (lang: %s), amount %d skip %d",
        req.params.lang, amount, skip);

    if(!validLanguage(req.params.lang))
        return { json: LanguageError };

    return mongo
        .readLimit(nconf.get('schema').labels, { lang: req.params.lang }, { when: -1 }, amount, skip)
        .then(function(data) {
            debug("retrived %d objects, with amount %d skip %d", _.size(data), amount, skip);
            return { json: data };
        })
        .catch(function(e) {
            debug("data (error): %s", e);
            return { 'text': `error: ${e}` };
        });
};

function semantics(req) {
    const { amount, skip } = params.optionParsing(req.params.paging, 100);
    debug("semantic request (lang: %s), amount %d skip %d",
        req.params.lang, amount, skip);

    if(!validLanguage(req.params.lang))
        return { json: LanguageError };

    return mongo
        .readLimit(nconf.get('schema').semantics, { lang: req.params.lang }, { when: -1 }, amount, skip)
        .then(function(data) {
            debug("retrived %d objects, with amount %d skip %d", _.size(data), amount, skip);
            return { json: data };
        })
        .catch(function(e) {
            debug("data (error): %s", e);
            return { 'text': `error: ${e}` };
        });
};

function redactEnriched(enrich) {
    _.unset(enrich, '_id');
    let s = _.first(enrich.summary);
    _.unset(s, '_id');
    _.unset(s, 'id');
    _.unset(s, 'user');
    _.unset(s, 'timeline');
    _.unset(s, 'impressionOrder');
    _.unset(s, 'impressionTime');
    enrich.summary = s;
    // XXX maybe can be redacted the condition of the ❌ below
    return enrich;
}

function enrich(req) {
    const DEFAULTAMOUNT = 13;
    const backintime = moment().subtract(2, 'd').toISOString();
    const { amount, skip } = params.optionParsing(req.params.paging, DEFAULTAMOUNT);
    debug("enrich request (lang: %s), amount %d skip %d",
        req.params.lang, amount, skip);

    if(!validLanguage(req.params.lang))
        return { json: LanguageError };

    return mongo
        .aggregate(nconf.get('schema').labels, [
            { $sort: { when: -1 }},
            { $match: { lang: req.params.lang, when: { "$lt": new Date(backintime) }} },
            { $skip: skip },
            { $limit: amount },
            { $lookup: { from: 'summary', localField: 'semanticId', foreignField: 'semanticId', as: 'summary' }}
        ])
        .map(redactEnriched)
        .then(function(enriched) {
            debug("return enrich, %d objects (%j)", _.size(enriched), _.map(enriched, function(e) {
                if(!e.summary || !e.summary.source || !e.summary.nature)
                    return "❌";
                return [ e.summary.source, e.summary.nature ];
            }));
            return { json: enriched };
        });
};

function noogle(req) {
    const DEFAULTAMOUNT = 13;
    const { amount, skip } = params.optionParsing(req.params.paging, DEFAULTAMOUNT);
    debug("noogle request (lang: %s, title: %s), amount %d skip %d",
        req.params.lang, req.params.label, amount, skip);

    if(!validLanguage(req.params.lang))
        return { json: LanguageError };

    return mongo
        .aggregate(nconf.get('schema').semantics, [
            { $sort: { when: -1 }},
            { $match: { lang: req.params.lang, title: req.params.label }},
            { $group: { _id: "$semanticId" }},
            { $skip: skip },
            { $limit: amount },
            { $lookup: { from: 'summary', localField: '_id', foreignField: 'semanticId', as: 'summary' }},
            { $lookup: { from: 'labels', localField: '_id', foreignField: 'semanticId', as: 'labels' }}
        ])
        .map(function(dirty) {
            let base = _.first(dirty.labels);
            base.summary = dirty.summary;
            base.when = moment(base.when);
            return base;
        })
        .map(redactEnriched)
        .then(function(results) {
            /*
            debug("return noogle, %d objects (%j)", _.size(results), _.map(results, function(e) {
                if(!e.summary || !e.summary.source || !e.summary.nature)
                    return "❌";
                return [ e.summary.source, e.summary.nature ];
            }));
            */
            const ordered = _.orderBy(results, {when: -1 });
            return { json: results };
        });
};

function loud(req) {
    const MAXENTRIES = 2000;
    const DEFAULTAMOUNT = 13;
    const backintime = moment().subtract(2, 'd').toISOString();
    const { amount, skip } = params.optionParsing(req.params.paging, DEFAULTAMOUNT);
    debug("loud request (lang: %s), amount %d skip %d",
        req.params.lang, amount, skip);

    if(!validLanguage(req.params.lang))
        return { json: LanguageError };

    return loudKeywordsPipeline(MAXENTRIES, backintime, amount, skip, req.params.lang)
        .then(function(loudness) {
            debug("return loudness: %j", _.map(loudness, 'label'));
            return { json: loudness };
        });

};

function loudKeywordsPipeline(maxentries, backintime, amount, skip, lang) {
    return mongo
        .aggregate(nconf.get('schema').semantics, [
            { $match: { lang: lang, when: { "$gt": new Date(backintime) }} },
            { $limit: maxentries },
            { $group: { _id: '$title', wp: { $first: '$wp'}, count: { $sum: 1 }}},
            { $sort: { "count": -1 }},
            { $skip: skip },
            { $limit: amount },
            { $project: { "label": "$_id", _id: false, wp: true, count: true }}
        ]);
}

/* This is the cache block used by langinfo */
const cache = _.reduce(semantic.langMap, function(memo, langName, l) {
    _.set(memo, l, {
        langName,
        content: null,
        computedAt: null,
        next: null,
    });
    return memo;
}, {} );

/* This is part of the langinfo feature */
function formatReturn(lang, updated) {
    if(updated) {
        cache[lang].content = updated.content;
        cache[lang].computedAt = updated.computedAt;
        cache[lang].next = updated.next
    }
    return {
        json: {
            content: cache[lang].content,
            computedAt: cache[lang].computedAt.toISOString(),
            next: cache[lang].next.toISOString(),
        }
    };
};

function langinfo(req) {
    /* this API returns an complete information on a language population, with number of
     * active contributors in the last 48 hours and total keyword seen in the last 48 hours,
     * this API do not support paging and is meant to be cached */
    const MAXENTRIES = 60000;
    const DEFAULTAMOUNT = 10;
    const hoursNumber = 48;
    const backintime = moment().subtract(hoursNumber, 'h').toISOString();
    const amount = 13;
    const skip = 0;
    const lang = req.params.lang;
    const cacheMinutes = 60 * 12;

    if(!validLanguage(lang))
        return { json: LanguageError };

    if(cache[lang].next && moment().isBefore(cache[lang].next) && cache[lang].content) {
        debug("langInfo %s, using cached version", lang);
        return formatReturn(lang);
    }

    debug("langInfo %s, retrieving from DB", lang);
    return Promise.all([
        loudKeywordsPipeline(MAXENTRIES, backintime, amount, skip, lang),
        mongo.aggregate(nconf.get('schema').semantics, [
            { $sort: { when: -1 }},
            { $match: { lang: req.params.lang, when: { "$gt": new Date(backintime) } }},
            { $limit: MAXENTRIES },
            { $group: { _id: "$label" }},
            { $group: { _id: null, amount: { "$sum": 1 } }},
        ]).then(function(o) { return (o && o[0] && o[0].amount) ? o[0].amount : 0 }),
        mongo.aggregate(nconf.get('schema').labels, [
            { $sort: { when: -1 }},
            { $match: { lang: lang, when: { "$gt": new Date(backintime) } }},
            { $limit: MAXENTRIES },
            { $lookup: { from: 'summary', localField: 'semanticId', foreignField: 'semanticId', as: 'summary' }},
            { $group: { _id: "dummy", profiles: { $addToSet: "$summary.user"} }}
        ]).then(function(usermess) {
            // remind/TODO grouped by size and anonymized, this can be a nice stats
            // _.flatten(usermess[0].profiles)
            if(!(usermess && usermess[0] && usermess[0].profiles))
                return 0;
            return _.size(_.uniq(_.flatten(usermess[0].profiles)))
        })
    ])
    .then(function(results) {
        let retval = {
            consideredHoursWindow: hoursNumber,
            language: req.params.lang,
            most: _.map(results[0], 'label'),
            labelsCount: results[1],
            contributors: results[2],
        };
        return formatReturn(lang, {
            content: retval,
            computedAt: moment(),
            next: moment().add(cacheMinutes, 'minutes')
        });
    });
}

function languages(req) {
    return various
        .loadJSONfile('rss/keywords/available.json')
        .then(function(available) {
            debug("Loaded %d available on %d potential",
                _.size(available), _.size(semantic.langMap));
            return {
                json: {
                    available,
                    potential: semantic.langMap
                }
            };
        });
};

function keywords(req) {
    const lc = req.params.lang;
    debug("keywords request for %s", lc);
    if(!validLanguage(lc))
        return { json: LanguageError };
    return various
        .loadJSONfile(`rss/keywords/${lc}.json`)
        .then(function(kwds) {
            debug("%d keywords returned as part of %s",
                _.size(kwds), lc);
            return { json: kwds };
        });
};

module.exports = {
    labels,
    semantics,
    enrich,
    loud,
    noogle,
    langinfo,
    languages,
    keywords
};
<|endoftext|>


<commit_before>import { EventEmitter } from 'events';

export default class Reconnector extends EventEmitter {
  constructor() {
    super();

    this._class = null;
    this._url = null;
    this._protocols = null;
    this._options = null;

    this._codes = [1000, 1001, 1006];
    this._maxAttempts = 10;

    this._attempts = 0;
    this._factor = 1;
    this._timeout = null;

    this._handleClose = (e) => this._close(e);
    this._handleError = (e) => this._error(e);
    this._handleOpen = (e) => this._open(e);
  }

  class(value = null) {
    if (value === null) {
      return this._class;
    }

    this._class = value;
    return this;
  }

  url(value = null) {
    if (value === null) {
      return this._url;
    }

    this._url = value;
    return this;
  }

  protocols(value = null) {
    if (value === null) {
      return this._protocols;
    }

    this._protocols = value;
    return this;
  }

  options(value = null) {
    if (value === null) {
      return this._options;
    }

    this._options = value;
    return this;
  }

  codes(value = null) {
    if (value === null) {
      return this._codes;
    }

    this._codes = value;
    return this;
  }

  attempts(value = null) {
    if (value === null) {
      return this._maxAttempts;
    }

    this._maxAttempts = value;
    return this;
  }

  factor(value = null) {
    if (value === null) {
      return this._factor;
    }

    this._factor = value;
    return this;
  }

  open() {
    clearTimeout(this._timeout);

    this._websocket = new this._class(this._url, this._protocols,
      this._options);

    if (!this._websocket.removeEventListener) {
      this._websocket.removeEventListener = this._websocket.removeListener;
    }

    this._bindSocket();
  }

  _bindSocket() {
    this._websocket.addEventListener('close', this._handleClose);
    this._websocket.addEventListener('error', this._handleError);
    this._websocket.addEventListener('open', this._handleOpen);
  }

  _unbindSocket() {
    this._websocket.removeEventListener('close', this._handleClose);
    this._websocket.removeEventListener('error', this._handleError);
    this._websocket.removeEventListener('open', this._handleOpen);
  }

  _close(event) {
    this._unbindSocket();

    if (this._codes.indexOf(event.code) !== -1 &&
      this._maxAttempts === -1 ||
      this._attempts < this._maxAttempts) {

      this._reconnect(event);
      return;
    }

    this.emit('close');
  }

  _error(error) {
    if (error.code === 'ECONNREFUSED') {
      return;
    }

    this.emit('error', error);
  }

  _open(event) {
    event.attempts = this._attempts;
    event.socket = this._websocket;

    this._attempts = 0;

    this.emit('open', event);
  }

  _reconnect(event) {
    let delay = Math.pow(this._factor, this._attempts);
    this._attempts += 1;

    if (event.reason) {
      const match = event.reason.match(/delay=(\d+)/);

      if (match) {
        delay = Number(match[1]);
      }
    }

    event.attempt = this._attempts;
    event.delay = delay * 1000;

    this._timeout = setTimeout(() => this.open(), event.delay);

    this.emit('reconnect', event);
  }
}
<commit_msg>Mute errors, use factory not class, refactor<commit_after>import { EventEmitter } from 'events';

export default class Reconnector extends EventEmitter {
  constructor() {
    super();

    this._factory = null;
    this._url = null;
    this._protocols = null;
    this._options = null;

    this._codes = [1000, 1001, 1006];
    this._maxAttempts = 10;

    this._attempts = 0;
    this._factor = 1;
    this._timeout = null;

    this._handleClose = (e) => this._close(e);
    this._handleError = () => {};
    this._handleOpen = (e) => this._open(e);
  }

  factory(value = null) {
    if (value === null) {
      return this._factory;
    }

    this._factory = value;
    return this;
  }

  url(value = null) {
    if (value === null) {
      return this._url;
    }

    this._url = value;
    return this;
  }

  protocols(value = null) {
    if (value === null) {
      return this._protocols;
    }

    this._protocols = value;
    return this;
  }

  options(value = null) {
    if (value === null) {
      return this._options;
    }

    this._options = value;
    return this;
  }

  codes(value = null) {
    if (value === null) {
      return this._codes;
    }

    this._codes = value;
    return this;
  }

  attempts(value = null) {
    if (value === null) {
      return this._maxAttempts;
    }

    this._maxAttempts = value;
    return this;
  }

  factor(value = null) {
    if (value === null) {
      return this._factor;
    }

    this._factor = value;
    return this;
  }

  open() {
    clearTimeout(this._timeout);

    this._websocket = this._factory(this._url,
      this._protocols, this._options);

    this._websocket.removeEventListener =
      this._websocket.removeEventListener ||
      this._websocket.removeListener;

    this._bindSocket();
  }

  _bindSocket() {
    this._websocket.addEventListener('close', this._handleClose);
    this._websocket.addEventListener('error', this._handleError);
    this._websocket.addEventListener('open', this._handleOpen);
  }

  _unbindSocket() {
    this._websocket.removeEventListener('close', this._handleClose);
    this._websocket.removeEventListener('error', this._handleError);
    this._websocket.removeEventListener('open', this._handleOpen);
  }

  _close(event) {
    this._unbindSocket();

    const reconnect = this._codes.indexOf(event.code) !== -1 &&
      this._maxAttempts === -1 ||
      this._attempts < this._maxAttempts;

    if (reconnect) {
      this._reconnect(event);
      return;
    }

    this.emit('close');
  }

  _open(event) {
    event.attempts = this._attempts;
    event.socket = this._websocket;

    this._attempts = 0;

    this.emit('open', event);
  }

  _reconnect(event) {
    let delay = Math.pow(this._factor, this._attempts);
    this._attempts += 1;

    if (event.reason) {
      const match = event.reason.match(/delay=(\d+)/);
      delay = match ? Number(match[1]) : delay;
    }

    this._timeout = setTimeout(() => this.open(), delay * 1000);
  }
}
<|endoftext|>


<commit_before>angular.module('compass.cluster', [
    'ui.router',
    'ui.bootstrap',
    'compass.charts',
    'ngAnimate',
    'ngTable',
    'angular-rickshaw'
])

.config(function($stateProvider, $urlRouterProvider) {
    $stateProvider
        .state('cluster', {
            url: '/cluster/{id}',
            controller: 'clusterCtrl',
            templateUrl: 'src/app/cluster/cluster.tpl.html',
            authenticate: true
        })
        .state('cluster.overview', {
            url: '/overview',
            controller: 'clusterProgressCtrl',
            templateUrl: 'src/app/cluster/cluster-overview.tpl.html',
            authenticate: true
        })
        .state('cluster.config', {
            url: '/config',
            controller: 'configurationCtrl',
            templateUrl: 'src/app/cluster/cluster-config.tpl.html',
            authenticate: true
        })
        .state('cluster.config.security', {
            url: '/security',
            templateUrl: 'src/app/cluster/cluster-security.tpl.html',
            authenticate: true
        })
        .state('cluster.config.network', {
            url: '/network',
            templateUrl: 'src/app/cluster/cluster-network.tpl.html',
            authenticate: true
        })
        .state('cluster.config.partition', {
            url: '/partition',
            templateUrl: 'src/app/cluster/cluster-partition.tpl.html',
            authenticate: true
        })
        .state('cluster.config.roles', {
            url: '/roles',
            templateUrl: 'src/app/cluster/cluster-roles.tpl.html',
            authenticate: true
        })
        .state('cluster.log', {
            url: '/log',
            templateUrl: 'src/app/cluster/cluster-log.tpl.html',
            authenticate: true
        })
        .state('cluster.monitoring', {
            url: '/monitoring',
            templateUrl: 'src/app/cluster/cluster-monitoring.tpl.html',
            authenticate: true
        });
})

.controller('clusterCtrl', function($scope, $state, dataService, stateService, $stateParams) {
    $scope.clusterId = $stateParams.id;
    $scope.state = $state;

    dataService.getClusterById($scope.clusterId).success(function(data) {
        $scope.clusterInfo = data;
    });

    dataService.getMonitoringNav().success(function(data) {
        $scope.monitoringNav = data;
        stateService.addStates($scope.monitoringNav);
    });

}).directive('clusternav', function() {
    return {
        templateUrl: 'src/app/cluster/cluster-nav.tpl.html'
    }
})

.controller('clusterProgressCtrl', function($scope, dataService, $stateParams, $filter, ngTableParams, $timeout, $modal) {
    var clusterId = $stateParams.id;
    var progressTimer;
    var fireTimer = true;

    var getClusterProgress = function() {
        dataService.getClusterProgress(clusterId).success(function(data) {
            $scope.clusterProgress = data;
            //if ($scope.clusterProgress.state == "INSTALLING") {
            if (fireTimer) {
                progressTimer = $timeout(getClusterProgress, 5000);
            }
            //}
        });
    }

    getClusterProgress();

    dataService.getServerColumns().success(function(data) {
        $scope.server_columns = data.progress;
    });

    dataService.getClusterHostMachines(clusterId).success(function(data) {
        $scope.hosts = data;

        $scope.tableParams = new ngTableParams({
            page: 1, // show first page
            count: $scope.hosts.length + 1 // count per page
        }, {
            counts: [], // hide count-per-page box
            total: $scope.hosts.length, // length of data
            getData: function($defer, params) {
                // use build-in angular filter
                var orderedData = params.sorting() ?
                    $filter('orderBy')($scope.hosts, params.orderBy()) : $scope.hosts;

                $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
            }
        });

        $scope.deleteHost = function(index) {
            dataService.deleteHost($scope.hosts[index].id)
            $scope.hosts.splice(index, 1);
            $scope.tableParams.reload();
        };
    });

    $scope.selectAllServers = function(flag) {
        if (flag) {
            angular.forEach($scope.hosts, function(sv) {
                sv.selected = true;
            })
        } else {
            angular.forEach($scope.hosts, function(sv) {
                sv.selected = false;
            })
        }
    };

    $scope.openDeleteHostModal = function(index) {
        var modalInstance = $modal.open({
            templateUrl: 'deleteHostConfirm.html',
            controller: deleteHostModalCtrl,
            resolve: {
                host: function() {
                    return $scope.hosts[index];
                }
            }
        });

        modalInstance.result.then(function() {
            // ok
            $scope.deleteHost(index);
        }, function() {
            // cancel
        });
    };

    $scope.$on('$destroy', function() {
        fireTimer = false;
        $timeout.cancel(progressTimer);
    });

})

.controller('createClusterCtrl', ['$scope', '$state', '$modal', '$log', 'dataService', 'wizardFactory',
    function($scope, $state, $modal, $log, dataService, wizardFactory) {
        dataService.getAdapters().success(function(data) {
            $scope.allAdapters = data;
            $scope.cluster = {};

            $scope.open = function(size) {
                var modalInstance = $modal.open({
                    templateUrl: 'createClusterModal.html',
                    controller: ModalInstanceCtrl,
                    size: size,
                    resolve: {
                        allAdapters: function() {
                            return $scope.allAdapters;
                        },
                        cluster: function() {
                            return $scope.cluster;
                        }
                    }
                });

                modalInstance.result.then(function(cluster) {
                    $scope.cluster = cluster;
                    dataService.createCluster(cluster).success(function(data, status) {
                        wizardFactory.setClusterInfo(data);
                        angular.forEach($scope.allAdapters, function(adapter) {
                            if (adapter.id == $scope.cluster.adapter_id) {
                                wizardFactory.setAdapter(adapter);
                            }
                        })
                        $state.go('wizard', {
                            "id": data.id,
                            "config": "true"
                        });
                        $scope.cluster = {};
                    });
                }, function() {
                    // modal cancelled
                });
            };
        });
    }
])

.controller('monitoringCtrl', ['$scope',
    function($scope) {
        $scope.options = {
            renderer: 'area'
        };
        $scope.features = {
            hover: {
                xFormatter: function(x) {
                    return 't=' + x;
                },
                yFormatter: function(y) {
                    return '$' + y;
                }
            }
        };
        $scope.series = [{
            name: 'Series 1',
            color: 'steelblue',
            data: [{
                x: 0,
                y: 23
            }, {
                x: 1,
                y: 15
            }, {
                x: 2,
                y: 79
            }, {
                x: 3,
                y: 31
            }, {
                x: 4,
                y: 60
            }]
        }, {
            name: 'Series 2',
            color: 'lightblue',
            data: [{
                x: 0,
                y: 30
            }, {
                x: 1,
                y: 20
            }, {
                x: 2,
                y: 64
            }, {
                x: 3,
                y: 50
            }, {
                x: 4,
                y: 15
            }]
        }];

        $scope.options2 = {
            renderer: 'line'
        };
        $scope.features2 = {
            hover: {
                xFormatter: function(x) {
                    return 't=' + x;
                },
                yFormatter: function(y) {
                    return '$' + y;
                }
            }
        };
        $scope.series2 = [{
            name: 'Series 1',
            color: 'steelblue',
            data: [{
                x: 0,
                y: 23
            }, {
                x: 1,
                y: 15
            }, {
                x: 2,
                y: 79
            }, {
                x: 3,
                y: 31
            }, {
                x: 4,
                y: 60
            }]
        }, {
            name: 'Series 2',
            color: 'lightblue',
            data: [{
                x: 0,
                y: 30
            }, {
                x: 1,
                y: 20
            }, {
                x: 2,
                y: 64
            }, {
                x: 3,
                y: 50
            }, {
                x: 4,
                y: 15
            }]
        }];
    }
])

.controller('configurationCtrl', ['$scope', 'dataService', '$stateParams', '$filter', 'ngTableParams',
    function($scope, dataService, $stateParams, $filter, ngTableParams) {
        var clusterId = $stateParams.id;
        $scope.partitionarray = [];
        dataService.getClusterConfig(clusterId).success(function(data) {
            $scope.configuration = data;

            angular.forEach($scope.configuration.os_config.partition, function(value, key) {
                $scope.partitionarray.push({
                    "name": key,
                    "number": value.percentage
                });
            });

        });

        dataService.getServerColumns().success(function(data) {
            $scope.server_columns = data.roles;
        });

        dataService.getClusterHostMachines(clusterId).success(function(data) {
            $scope.hosts = data;

            $scope.tableParams = new ngTableParams({
                page: 1, // show first page
                count: $scope.hosts.length + 1 // count per page
            }, {
                counts: [], // hide count-per-page box
                total: $scope.hosts.length, // length of data
                getData: function($defer, params) {
                    // use build-in angular filter
                    var orderedData = params.sorting() ?
                        $filter('orderBy')($scope.hosts, params.orderBy()) : $scope.hosts;

                    $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
                }
            });
        });

    }
])

var ModalInstanceCtrl = function($scope, $modalInstance, allAdapters, cluster) {
    $scope.allAdapters = allAdapters;
    $scope.cluster = cluster;

    $scope.$watch('cluster.adapter_id', function() {
        angular.forEach($scope.allAdapters, function(adapter) {
            if (adapter.id == $scope.cluster.adapter_id) {
                $scope.supported_oses = adapter.supported_oses;
            }
        })
    });

    $scope.ok = function() {
        $scope.result = 'ok';
        $modalInstance.close($scope.cluster);
    };

    $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
        $scope.result = 'cancel';
    };
};

var deleteHostModalCtrl = function($scope, $modalInstance, host) {
    $scope.host = host;
    $scope.ok = function() {
        $modalInstance.close();
    };
    $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
    };
}
<commit_msg>Fix sidebar touch event on iPad<commit_after>angular.module('compass.cluster', [
    'ui.router',
    'ui.bootstrap',
    'compass.charts',
    'ngAnimate',
    'ngTable',
    'angular-rickshaw'
])

.config(function($stateProvider, $urlRouterProvider) {
    $stateProvider
        .state('cluster', {
            url: '/cluster/{id}',
            controller: 'clusterCtrl',
            templateUrl: 'src/app/cluster/cluster.tpl.html',
            authenticate: true
        })
        .state('cluster.overview', {
            url: '/overview',
            controller: 'clusterProgressCtrl',
            templateUrl: 'src/app/cluster/cluster-overview.tpl.html',
            authenticate: true
        })
        .state('cluster.config', {
            url: '/config',
            controller: 'configurationCtrl',
            templateUrl: 'src/app/cluster/cluster-config.tpl.html',
            authenticate: true
        })
        .state('cluster.config.security', {
            url: '/security',
            templateUrl: 'src/app/cluster/cluster-security.tpl.html',
            authenticate: true
        })
        .state('cluster.config.network', {
            url: '/network',
            templateUrl: 'src/app/cluster/cluster-network.tpl.html',
            authenticate: true
        })
        .state('cluster.config.partition', {
            url: '/partition',
            templateUrl: 'src/app/cluster/cluster-partition.tpl.html',
            authenticate: true
        })
        .state('cluster.config.roles', {
            url: '/roles',
            templateUrl: 'src/app/cluster/cluster-roles.tpl.html',
            authenticate: true
        })
        .state('cluster.log', {
            url: '/log',
            templateUrl: 'src/app/cluster/cluster-log.tpl.html',
            authenticate: true
        })
        .state('cluster.monitoring', {
            url: '/monitoring',
            templateUrl: 'src/app/cluster/cluster-monitoring.tpl.html',
            authenticate: true
        });
})

.controller('clusterCtrl', function($scope, $state, dataService, stateService, $stateParams) {
    $scope.clusterId = $stateParams.id;
    $scope.state = $state;

    dataService.getClusterById($scope.clusterId).success(function(data) {
        $scope.clusterInfo = data;
    });

    dataService.getMonitoringNav().success(function(data) {
        $scope.monitoringNav = data;
        stateService.addStates($scope.monitoringNav);
    });

}).directive('clusternav', function($timeout) {
    return {
        restrict: 'EAC',
        templateUrl: 'src/app/cluster/cluster-nav.tpl.html',
        link: function($scope, elem, attrs) {
            $timeout(function() {
                $('.nav-list ul a').on('click touchend', function(e) {
                    var el = $(this);
                    var link = el.attr('href');
                    window.location = link;
                });
            }, 0);

            elem.bind('$destroy', function() {
                $('.nav-list ul a').off('click touchend');
            });
        }
    }
})

.controller('clusterProgressCtrl', function($scope, dataService, $stateParams, $filter, ngTableParams, $timeout, $modal) {
    var clusterId = $stateParams.id;
    var progressTimer;
    var fireTimer = true;

    var getClusterProgress = function() {
        dataService.getClusterProgress(clusterId).success(function(data) {
            $scope.clusterProgress = data;
            //if ($scope.clusterProgress.state == "INSTALLING") {
            if (fireTimer) {
                progressTimer = $timeout(getClusterProgress, 5000);
            }
            //}
        });
    }

    getClusterProgress();

    dataService.getServerColumns().success(function(data) {
        $scope.server_columns = data.progress;
    });

    dataService.getClusterHostMachines(clusterId).success(function(data) {
        $scope.hosts = data;

        $scope.tableParams = new ngTableParams({
            page: 1, // show first page
            count: $scope.hosts.length + 1 // count per page
        }, {
            counts: [], // hide count-per-page box
            total: $scope.hosts.length, // length of data
            getData: function($defer, params) {
                // use build-in angular filter
                var orderedData = params.sorting() ?
                    $filter('orderBy')($scope.hosts, params.orderBy()) : $scope.hosts;

                $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
            }
        });

        $scope.deleteHost = function(index) {
            dataService.deleteHost($scope.hosts[index].id)
            $scope.hosts.splice(index, 1);
            $scope.tableParams.reload();
        };
    });

    $scope.selectAllServers = function(flag) {
        if (flag) {
            angular.forEach($scope.hosts, function(sv) {
                sv.selected = true;
            })
        } else {
            angular.forEach($scope.hosts, function(sv) {
                sv.selected = false;
            })
        }
    };

    $scope.openDeleteHostModal = function(index) {
        var modalInstance = $modal.open({
            templateUrl: 'deleteHostConfirm.html',
            controller: deleteHostModalCtrl,
            resolve: {
                host: function() {
                    return $scope.hosts[index];
                }
            }
        });

        modalInstance.result.then(function() {
            // ok
            $scope.deleteHost(index);
        }, function() {
            // cancel
        });
    };

    $scope.$on('$destroy', function() {
        fireTimer = false;
        $timeout.cancel(progressTimer);
    });

})

.controller('createClusterCtrl', ['$scope', '$state', '$modal', '$log', 'dataService', 'wizardFactory',
    function($scope, $state, $modal, $log, dataService, wizardFactory) {
        dataService.getAdapters().success(function(data) {
            $scope.allAdapters = data;
            $scope.cluster = {};

            $scope.open = function(size) {
                var modalInstance = $modal.open({
                    templateUrl: 'createClusterModal.html',
                    controller: ModalInstanceCtrl,
                    size: size,
                    resolve: {
                        allAdapters: function() {
                            return $scope.allAdapters;
                        },
                        cluster: function() {
                            return $scope.cluster;
                        }
                    }
                });

                modalInstance.result.then(function(cluster) {
                    $scope.cluster = cluster;
                    dataService.createCluster(cluster).success(function(data, status) {
                        wizardFactory.setClusterInfo(data);
                        angular.forEach($scope.allAdapters, function(adapter) {
                            if (adapter.id == $scope.cluster.adapter_id) {
                                wizardFactory.setAdapter(adapter);
                            }
                        })
                        $state.go('wizard', {
                            "id": data.id,
                            "config": "true"
                        });
                        $scope.cluster = {};
                    });
                }, function() {
                    // modal cancelled
                });
            };
        });
    }
])

.controller('monitoringCtrl', ['$scope',
    function($scope) {
        $scope.options = {
            renderer: 'area'
        };
        $scope.features = {
            hover: {
                xFormatter: function(x) {
                    return 't=' + x;
                },
                yFormatter: function(y) {
                    return '$' + y;
                }
            }
        };
        $scope.series = [{
            name: 'Series 1',
            color: 'steelblue',
            data: [{
                x: 0,
                y: 23
            }, {
                x: 1,
                y: 15
            }, {
                x: 2,
                y: 79
            }, {
                x: 3,
                y: 31
            }, {
                x: 4,
                y: 60
            }]
        }, {
            name: 'Series 2',
            color: 'lightblue',
            data: [{
                x: 0,
                y: 30
            }, {
                x: 1,
                y: 20
            }, {
                x: 2,
                y: 64
            }, {
                x: 3,
                y: 50
            }, {
                x: 4,
                y: 15
            }]
        }];

        $scope.options2 = {
            renderer: 'line'
        };
        $scope.features2 = {
            hover: {
                xFormatter: function(x) {
                    return 't=' + x;
                },
                yFormatter: function(y) {
                    return '$' + y;
                }
            }
        };
        $scope.series2 = [{
            name: 'Series 1',
            color: 'steelblue',
            data: [{
                x: 0,
                y: 23
            }, {
                x: 1,
                y: 15
            }, {
                x: 2,
                y: 79
            }, {
                x: 3,
                y: 31
            }, {
                x: 4,
                y: 60
            }]
        }, {
            name: 'Series 2',
            color: 'lightblue',
            data: [{
                x: 0,
                y: 30
            }, {
                x: 1,
                y: 20
            }, {
                x: 2,
                y: 64
            }, {
                x: 3,
                y: 50
            }, {
                x: 4,
                y: 15
            }]
        }];
    }
])

.controller('configurationCtrl', ['$scope', 'dataService', '$stateParams', '$filter', 'ngTableParams',
    function($scope, dataService, $stateParams, $filter, ngTableParams) {
        var clusterId = $stateParams.id;
        $scope.partitionarray = [];
        dataService.getClusterConfig(clusterId).success(function(data) {
            $scope.configuration = data;

            angular.forEach($scope.configuration.os_config.partition, function(value, key) {
                $scope.partitionarray.push({
                    "name": key,
                    "number": value.percentage
                });
            });

        });

        dataService.getServerColumns().success(function(data) {
            $scope.server_columns = data.roles;
        });

        dataService.getClusterHostMachines(clusterId).success(function(data) {
            $scope.hosts = data;

            $scope.tableParams = new ngTableParams({
                page: 1, // show first page
                count: $scope.hosts.length + 1 // count per page
            }, {
                counts: [], // hide count-per-page box
                total: $scope.hosts.length, // length of data
                getData: function($defer, params) {
                    // use build-in angular filter
                    var orderedData = params.sorting() ?
                        $filter('orderBy')($scope.hosts, params.orderBy()) : $scope.hosts;

                    $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
                }
            });
        });

    }
])

var ModalInstanceCtrl = function($scope, $modalInstance, allAdapters, cluster) {
    $scope.allAdapters = allAdapters;
    $scope.cluster = cluster;

    $scope.$watch('cluster.adapter_id', function() {
        angular.forEach($scope.allAdapters, function(adapter) {
            if (adapter.id == $scope.cluster.adapter_id) {
                $scope.supported_oses = adapter.supported_oses;
            }
        })
    });

    $scope.ok = function() {
        $scope.result = 'ok';
        $modalInstance.close($scope.cluster);
    };

    $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
        $scope.result = 'cancel';
    };
};

var deleteHostModalCtrl = function($scope, $modalInstance, host) {
    $scope.host = host;
    $scope.ok = function() {
        $modalInstance.close();
    };
    $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
    };
}
<|endoftext|>


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

'use strict';
var runScripts;

var transform = require('./fbtransform/lib/transform').transform;
var visitors = require('./fbtransform/visitors').transformVisitors;
var transform = transform.bind(null, visitors.react);
var docblock = require('./fbtransform/lib/docblock');

exports.transform = transform;
exports.exec = function(code) {
  return eval(transform(code));
};
var run = exports.run = function(code) {
  var moduleName =
    docblock.parseAsObject(docblock.extract(code)).providesModule;
  var jsx =
    docblock.parseAsObject(docblock.extract(code)).jsx;

  window.moduleLoads = (window.moduleLoads || []).concat(moduleName);
  window.startTime = Date.now();
  var functionBody = jsx ? transform(code).code : code;
  Function('require', 'module', 'exports', functionBody)(require, module, exports);
  window.endTime = Date.now();
  require[moduleName] = module.exports;
};

if (typeof window === "undefined" || window === null) {
  return;
}

var load = exports.load = function(url, callback) {
  var xhr;
  xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP') : new XMLHttpRequest();
  xhr.open('GET', url, false);
  if ('overrideMimeType' in xhr) {
    xhr.overrideMimeType('text/plain');
  }
  xhr.onreadystatechange = function() {
    var _ref;
    if (xhr.readyState === 4) {
      if ((_ref = xhr.status) === 0 || _ref === 200) {
        run(xhr.responseText);
      } else {
        throw new Error("Could not load " + url);
      }
      if (callback) {
        return callback();
      }
    }
  };
  return xhr.send(null);
};

runScripts = function() {
  var jsxes, execute, index, length, s, scripts;
  scripts = document.getElementsByTagName('script');
  jsxes = (function() {
    var _i, _len, _results;
    _results = [];
    for (_i = 0, _len = scripts.length; _i < _len; _i++) {
      s = scripts[_i];
      if (s.type === 'text/jsx') {
        _results.push(s);
      }
    }
    return _results;
  })();
  index = 0;
  length = jsxes.length;
  (execute = function(j) {
    var script;
    script = jsxes[j];
    if ((script != null ? script.type : void 0) === 'text/jsx') {
      if (script.src) {
         return load(script.src, execute);
      } else {
        run(script.innerHTML);
        return execute();
      }
    }
  });
  for (var i = 0; i < jsxes.length; i++) {
    execute(i);
  }
  return null;
};

if (window.addEventListener) {
  window.addEventListener('DOMContentLoaded', runScripts, false);
} else {
  window.attachEvent('onload', runScripts);
}
<commit_msg>Improve JSXTransformer<commit_after>/**
 * Copyright 2013 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* jshint browser: true */
/* jslint evil: true */

'use strict';
var runScripts;

var transform = require('./fbtransform/lib/transform').transform;
var visitors = require('./fbtransform/visitors').transformVisitors;
var transform = transform.bind(null, visitors.react);
var docblock = require('./fbtransform/lib/docblock');

var headEl = document.getElementsByTagName('head')[0];

exports.transform = transform;

exports.exec = function(code) {
  return eval(transform(code));
};

var run = exports.run = function(code) {
  var jsx = docblock.parseAsObject(docblock.extract(code)).jsx;

  var functionBody = jsx ? transform(code).code : code;
  var scriptEl = document.createElement('script');

  scriptEl.innerHTML = functionBody;
  headEl.appendChild(scriptEl);
};

if (typeof window === "undefined" || window === null) {
  return;
}

var load = exports.load = function(url, callback) {
  var xhr;
  xhr = window.ActiveXObject ? new window.ActiveXObject('Microsoft.XMLHTTP')
                             : new XMLHttpRequest();
  // Disable async since we need to execute scripts in the order they are in the
  // DOM to mirror normal script loading.
  xhr.open('GET', url, false);
  if ('overrideMimeType' in xhr) {
    xhr.overrideMimeType('text/plain');
  }
  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
      if (xhr.status === 0 || xhr.status === 200) {
        run(xhr.responseText);
      } else {
        throw new Error("Could not load " + url);
      }
      if (callback) {
        return callback();
      }
    }
  };
  return xhr.send(null);
};

runScripts = function() {
  var scripts = document.getElementsByTagName('script');
  scripts = Array.prototype.slice.call(scripts);
  var jsxScripts = scripts.filter(function(script) {
    return script.type === 'text/jsx';
  });

  jsxScripts.forEach(function(script) {
    if (script.src) {
      load(script.src);
    } else {
      run(script.innerHTML);
    }
  });
};

if (window.addEventListener) {
  window.addEventListener('DOMContentLoaded', runScripts, false);
} else {
  window.attachEvent('onload', runScripts);
}
<|endoftext|>


<commit_before>function PixelDrawr(settings) {
    "use strict";
    if(this === window) {
        return new PixelDrawr(settings);
    }
    var self = this,

        // A PixelRender object used to obtain raw sprite data and canvases
        PixelRender,

        // A MapScreenr variable to be used for bounds checking
        MapScreener,

        // The canvas object each refillGlobalCanvas call goes to
        canvas,

        // The 2D canvas context each refillGlobalCanvas call goes to
        context,

        // Arrays of Array[Thing]s that are to be drawn in each refillGlobalCanvas
        thing_arrays,

        // Utility function to create a canvas (typically taken from EightBittr)
        getCanvas,

        // The known viewport width, beyond which nothing should be drawn
        // SOON TO BE OBSOLUTE WHOOO
        innerWidth,

        unitsize,

        // A utility function to generate a class key to get an object sprite
        generateObjectKey,

        // Whether self.refillGlobalCanvas should skip redrawing the main canvas
        // every time.
        no_refill,

        // For refillQuadrant, an Array of string names to refill (bottom-to-top)
        group_names;

    self.reset = function(settings) {
        PixelRender = settings.PixelRender;
        MapScreener = settings.MapScreener;
        getCanvas = settings.getCanvas;
        unitsize = settings.unitsize || 4;
        no_refill = settings.no_refill;
        innerWidth = settings.innerWidth;
        group_names = settings.group_names;

        generateObjectKey = settings.generateObjectKey || function (object) {
            return object.toString();
        };
    }

    /* Simple sets
    */

    /**
     *
     */
    self.setThingArrays = function (arrays) {
        thing_arrays = arrays;
    }

    /**
     *
     */
    self.setCanvas = function (canvasNew) {
        canvas = canvasNew;
        context = canvas.getContext("2d");
        self.drawThingOnCanvasBound = self.drawThingOnCanvas.bind(self, context);
    }

    /**
     *
     */
    self.setInnerWidth = function (width) {
        innerWidth = width;
    };

    /**
     *
     */
    self.setNoRefill = function (enabled) {
        no_refill = enabled;
    };

    /* Core rendering
    */

    /**
     * Goes through all the motions of find and parsing a thing's sprite
     * This should be called whenever the sprite's appearance changes
     *
     * @param {Thing} thing   A thing whose sprite must be updated
     * @return {Self}
     */
    self.setThingSprite = function(thing) {
        // If it's set as hidden, or doesn't have a title, don't bother updating it
        if(thing.hidden || !thing.title) {
            return;
        }

        // PixelRender does most of the work in fetching the rendered sprite
        thing.sprite = PixelRender.decode(generateObjectKey(thing), thing);

        // To do: remove dependency on .num_sprites and sprite_type
        if(thing.sprite.multiple) {
          thing.sprite_type = thing.sprite.type;
          refillThingCanvasMultiple(thing, thing.sprite);
        }
        else {
          thing.num_sprites = 1;
          thing.sprite_type = "normal";
          refillThingCanvasSingle(thing, thing.sprite);
        }

        return self;
    }

    /**
     * Simply draws a thing's sprite to its canvas by getting and setting
     * a canvas::imageData object via context.getImageData(...).
     *
     * @param {Thing} thing   A thing whose .canvas must be updated
     * @return {Self}
     * @private
     */
    function refillThingCanvasSingle(thing) {
        if(thing.width < 1 || thing.height < 1) {
            return;
        }

        var canvas = thing.canvas,
            context = thing.context,
            imageData = context.getImageData(0, 0, canvas.width, canvas.height);

        PixelRender.memcpyU8(thing.sprite, imageData.data);
        context.putImageData(imageData, 0, 0);

        return self;
    }

    /**
     * For SpriteMultiples, this copies the sprite information for
     * each sub-sprite into its own canvas, and sets thing.sprites
     *
     * @param {Thing} thing   A thing whose .canvas and .sprites must be updated
     * @return {Self}
     * @private
     */
    function refillThingCanvasMultiple(thing) {
        var sprites_raw = thing.sprite,
            canvases = thing.canvases = {
                "direction": sprites_raw.direction,
                "multiple": true
            },
            canvas, context, imageData, i;

        thing.num_sprites = 1;

        for(i in sprites_raw.sprites) {
            // Make a new sprite for this individual component
            canvas = getCanvas(thing.spritewidth * unitsize, thing.spriteheight * unitsize);
            context = canvas.getContext("2d");

            // Copy over this sprite's information the same way as refillThingCanvas
            imageData = context.getImageData(0, 0, canvas.width, canvas.height);
            PixelRender.memcpyU8(sprites_raw.sprites[i], imageData.data);
            context.putImageData(imageData, 0, 0);

            // Record the canvas and context in thing.sprites
            canvases[i] = {
                canvas: canvas,
                context: context
            }
            thing.num_sprites += 1;
        }

      return canvases;
    }

    /* Core drawing
    */

    /**
     * Called every upkeep to refill the entire main canvas. All Thing arrays
     * are made to call self.refillThingArray in order.
     *
     * @param {string} background   The background to refill the context with
     *                              before drawing anything, unless no_refill is
     *                              enabled.
     *
     * @return {Self}
     */
    self.refillGlobalCanvas = function (background) {
        if(!no_refill) {
            context.fillStyle = background;
            context.fillRect(0, 0, canvas.width, canvas.height);
        }

        thing_arrays.forEach(self.refillThingArray);

        return self;
    };

    /**
     *
     *
     *
     */
    self.refillThingArray = function (array) {
        array.forEach(self.drawThingOnCanvasBound);
    };

    /**
     *
     */
    self.refillQuadrantGroups = function (groups, background) {
        for(var i = 0; i < groups.length; i += 1) {
            self.refillQuadrants(groups[i].quadrants, background);
        }
    };

    /**
     *
     */
    self.refillQuadrants = function (quadrants, background) {
        var quadrant, i;

        for(i = 0; i < quadrants.length; i += 1) {
            quadrant = quadrants[i];
            if(
                quadrant.changed
                && quadrant.top < MapScreener.height
                && quadrant.right > 0
                && quadrant.bottom > 0
                && quadrant.left < MapScreener.width
            ) {
                self.refillQuadrant(quadrant, background);
                context.drawImage(
                    quadrant.canvas,
                    quadrant.left,
                    quadrant.top
                );
            }
        }
    };

    /**
     *
     */
    self.refillQuadrant = function (quadrant, background) {
        var group, i, j;

        if(!no_refill) {
            quadrant.context.fillStyle = background;
            quadrant.context.fillRect(0, 0, quadrant.canvas.width, quadrant.canvas.height);
        }

        for(i = group_names.length - 1; i >= 0; i -= 1) {
            group = quadrant.things[group_names[i]];

            for(j = 0; j < group.length; j += 1) {
                self.drawThingOnQuadrant(group[j], quadrant);
            }
        }

        quadrant.changed = false;
    };

    /**
     * General function to draw a Thing to a context
     * This will call drawThingOnCanvas[Single/Multiple] with more arguments
     *
     * @return {Self}
     */
    self.drawThingOnCanvas = function(context, thing) {
        if(thing.hidden || thing.right < 0 || thing.left > innerWidth) {
            return;
        }

        // If there's just one sprite, it's pretty simple
        if(thing.num_sprites === 1) {
            return drawThingOnCanvasSingle(context, thing.canvas, thing, thing.left, thing.top);
        }
        // For multiple sprites, some calculations will be needed
        else {
            return drawThingOnCanvasMultiple(context, thing.canvases, thing, thing.left, thing.top);
        }
    }

    /**
     *
     */
    self.drawThingOnQuadrant = function (thing, quadrant) {
        if(thing.hidden) {
            return;
        }

        // If there's just one sprite, it's pretty simple
        if(thing.num_sprites === 1) {
            return drawThingOnCanvasSingle(quadrant.context, thing.canvas, thing, thing.left - quadrant.left, thing.top - quadrant.top);
        }
        // For multiple sprites, some calculations will be needed
        else {
            return drawThingOnCanvasMultiple(quadrant.context, thing.canvases, thing, thing.left - quadrant.left, thing.top - quadrant.top);
        }
    };

    /**
     * Draws a Thing's single canvas onto a context (called by self.drawThingOnCanvas).
     *
     * @param {CanvasRenderingContext2D} context
     * @param {Canvas} canvas
     * @param {Thing} thing
     * @param {Number} leftc
     * @param {Number} topc
     * @return {Self}
     * @private
     */
    function drawThingOnCanvasSingle(context, canvas, thing, leftc, topc) {
        // If the sprite should repeat, use the pattern equivalent
        if(thing.repeat) {
            drawPatternOnCanvas(context, canvas, leftc, topc, thing.unitwidth, thing.unitheight, thing.opacity || 1);
        }
        // Opacities not equal to one must reset the context afterwards
        else if(thing.opacity != 1) {
            context.globalAlpha = thing.opacity;
            context.drawImage(canvas, leftc, topc);
            context.globalAlpha = 1;
        } else {
            context.drawImage(canvas, leftc, topc);
        }

        return self;
    }

    /**
     * Draws a Thing's multiple canvases onto a context (called by self.drawThingOnCanvas)
     *
     * @return {Self}
     * @private
     */
    function drawThingOnCanvasMultiple(context, canvases, thing, leftc, topc) {
        var sprite = thing.sprite,
            topreal = topc,
            leftreal = leftc,
            rightreal = leftc + thing.unitwidth,
            bottomreal = topc + thing.unitheight,
            widthreal = thing.unitwidth,
            heightreal = thing.unitheight,
            spritewidthpixels = thing.spritewidthpixels,
            spriteheightpixels = thing.spriteheightpixels,
            opacity = thing.opacity,
            sdiff, canvasref;

        // Vertical sprites may have 'top', 'bottom', 'middle'
        switch(canvases.direction) {
            case "vertical":
                // If there's a bottom, draw that and push up bottomreal
                if((canvasref = canvases.bottom)) {
                    sdiff = sprite.bottomheight || spriteheightpixels;
                    drawPatternOnCanvas(context, canvasref.canvas, leftreal, bottomreal - sdiff, widthreal, Math.min(heightreal, spriteheightpixels), opacity);
                    bottomreal -= sdiff;
                    heightreal -= sdiff;
                }
                // If there's a top, draw that and push down topreal
                if((canvasref = canvases.top)) {
                    sdiff = sprite.topheight || spriteheightpixels;
                    drawPatternOnCanvas(context, canvasref.canvas, leftreal, topreal, widthreal, Math.min(heightreal, spriteheightpixels), opacity);
                    topreal += sdiff;
                    heightreal -= sdiff;
                }
            break;
            // Horizontal sprites may have 'left', 'right', 'middle'
            case "horizontal":
                // If there's a left, draw that and push up leftreal
                if((canvasref = canvases.left)) {
                    sdiff = sprite.leftwidth || spritewidthpixels;
                    drawPatternOnCanvas(context, canvasref.canvas, leftreal, topreal, Math.min(widthreal, spritewidthpixels), heightreal, opacity);
                    leftreal += sdiff;
                    widthreal -= sdiff;
                }
                // If there's a right, draw that and push back rightreal
                if((canvasref = canvases.right)) {
                    sdiff = sprite.rightwidth || spritewidthpixels;
                    drawPatternOnCanvas(context, canvasref.canvas, rightreal - sdiff, topreal, Math.min(widthreal, spritewidthpixels), heightreal, opacity);
                    rightreal -= sdiff;
                    widthreal -= sdiff;
                }
            break;
        }

        // If there's still room/*, and it exists*/, draw the actual canvas
        if((canvasref = canvases.middle) && topreal < bottomreal && leftreal < rightreal) {
            drawPatternOnCanvas(context, canvasref.canvas, leftreal, topreal, widthreal, heightreal, opacity);
        }

        return self;
    }

    /* Utilities
    */

    /**
     * Macro to draw a pattern onto a canvas because of how
     * often it's used by the regular draw functions.
     * Not a fan of this lack of control over pattern source coordinates...
     */
    function drawPatternOnCanvas(context, source, leftc, topc, width, height, opacity) {
        context.globalAlpha = opacity;
        context.translate(leftc, topc);
        context.fillStyle = context.createPattern(source, "repeat");
        context.fillRect(0, 0, width, height);
        context.translate(-leftc, -topc);
        context.globalAlpha = 1;
    }

    self.reset(settings || {});
}<commit_msg>No innerWidth, renamed drawThingOnCanvas -> Context<commit_after>function PixelDrawr(settings) {
    "use strict";
    if(this === window) {
        return new PixelDrawr(settings);
    }
    var self = this,

        // A PixelRender object used to obtain raw sprite data and canvases
        PixelRender,

        // A MapScreenr variable to be used for bounds checking
        MapScreener,

        // The canvas object each refillGlobalCanvas call goes to
        canvas,

        // The 2D canvas context each refillGlobalCanvas call goes to
        context,

        // Arrays of Array[Thing]s that are to be drawn in each refillGlobalCanvas
        thing_arrays,

        // Utility function to create a canvas (typically taken from EightBittr)
        getCanvas,

        unitsize,

        // A utility function to generate a class key to get an object sprite
        generateObjectKey,

        // Whether self.refillGlobalCanvas should skip redrawing the main canvas
        // every time.
        no_refill,

        // For refillQuadrant, an Array of string names to refill (bottom-to-top)
        group_names;

    self.reset = function(settings) {
        PixelRender = settings.PixelRender;
        MapScreener = settings.MapScreener;
        getCanvas = settings.getCanvas;
        unitsize = settings.unitsize || 4;
        no_refill = settings.no_refill;
        group_names = settings.group_names;

        generateObjectKey = settings.generateObjectKey || function (object) {
            return object.toString();
        };
    }

    /* Simple sets
    */

    /**
     *
     */
    self.setThingArrays = function (arrays) {
        thing_arrays = arrays;
    }

    /**
     *
     */
    self.setCanvas = function (canvasNew) {
        canvas = canvasNew;
        context = canvas.getContext("2d");
        self.drawThingOnContextBound = self.drawThingOnContext.bind(self, context);
    }

    /**
     *
     */
    self.setNoRefill = function (enabled) {
        no_refill = enabled;
    };

    /* Core rendering
    */

    /**
     * Goes through all the motions of find and parsing a thing's sprite
     * This should be called whenever the sprite's appearance changes
     *
     * @param {Thing} thing   A thing whose sprite must be updated
     * @return {Self}
     */
    self.setThingSprite = function(thing) {
        // If it's set as hidden, or doesn't have a title, don't bother updating it
        if(thing.hidden || !thing.title) {
            return;
        }

        // PixelRender does most of the work in fetching the rendered sprite
        thing.sprite = PixelRender.decode(generateObjectKey(thing), thing);

        // To do: remove dependency on .num_sprites and sprite_type
        if(thing.sprite.multiple) {
          thing.sprite_type = thing.sprite.type;
          refillThingCanvasMultiple(thing, thing.sprite);
        }
        else {
          thing.num_sprites = 1;
          thing.sprite_type = "normal";
          refillThingCanvasSingle(thing, thing.sprite);
        }

        return self;
    }

    /**
     * Simply draws a thing's sprite to its canvas by getting and setting
     * a canvas::imageData object via context.getImageData(...).
     *
     * @param {Thing} thing   A thing whose .canvas must be updated
     * @return {Self}
     * @private
     */
    function refillThingCanvasSingle(thing) {
        if(thing.width < 1 || thing.height < 1) {
            return;
        }

        var canvas = thing.canvas,
            context = thing.context,
            imageData = context.getImageData(0, 0, canvas.width, canvas.height);

        PixelRender.memcpyU8(thing.sprite, imageData.data);
        context.putImageData(imageData, 0, 0);

        return self;
    }

    /**
     * For SpriteMultiples, this copies the sprite information for
     * each sub-sprite into its own canvas, and sets thing.sprites
     *
     * @param {Thing} thing   A thing whose .canvas and .sprites must be updated
     * @return {Self}
     * @private
     */
    function refillThingCanvasMultiple(thing) {
        var sprites_raw = thing.sprite,
            canvases = thing.canvases = {
                "direction": sprites_raw.direction,
                "multiple": true
            },
            canvas, context, imageData, i;

        thing.num_sprites = 1;

        for(i in sprites_raw.sprites) {
            // Make a new sprite for this individual component
            canvas = getCanvas(thing.spritewidth * unitsize, thing.spriteheight * unitsize);
            context = canvas.getContext("2d");

            // Copy over this sprite's information the same way as refillThingCanvas
            imageData = context.getImageData(0, 0, canvas.width, canvas.height);
            PixelRender.memcpyU8(sprites_raw.sprites[i], imageData.data);
            context.putImageData(imageData, 0, 0);

            // Record the canvas and context in thing.sprites
            canvases[i] = {
                canvas: canvas,
                context: context
            }
            thing.num_sprites += 1;
        }

      return canvases;
    }

    /* Core drawing
    */

    /**
     * Called every upkeep to refill the entire main canvas. All Thing arrays
     * are made to call self.refillThingArray in order.
     *
     * @param {string} background   The background to refill the context with
     *                              before drawing anything, unless no_refill is
     *                              enabled.
     *
     * @return {Self}
     */
    self.refillGlobalCanvas = function (background) {
        if(!no_refill) {
            context.fillStyle = background;
            context.fillRect(0, 0, canvas.width, canvas.height);
        }

        thing_arrays.forEach(self.refillThingArray);

        return self;
    };

    /**
     *
     *
     *
     */
    self.refillThingArray = function (array) {
        array.forEach(self.drawThingOnContextBound);
    };

    /**
     *
     */
    self.refillQuadrantGroups = function (groups, background) {
        for(var i = 0; i < groups.length; i += 1) {
            self.refillQuadrants(groups[i].quadrants, background);
        }
    };

    /**
     *
     */
    self.refillQuadrants = function (quadrants, background) {
        var quadrant, i;

        for(i = 0; i < quadrants.length; i += 1) {
            quadrant = quadrants[i];
            if(
                quadrant.changed
                && quadrant.top < MapScreener.height
                && quadrant.right > 0
                && quadrant.bottom > 0
                && quadrant.left < MapScreener.width
            ) {
                self.refillQuadrant(quadrant, background);
                context.drawImage(
                    quadrant.canvas,
                    quadrant.left,
                    quadrant.top
                );
            }
        }
    };

    /**
     *
     */
    self.refillQuadrant = function (quadrant, background) {
        var group, i, j;

        if(!no_refill) {
            quadrant.context.fillStyle = background;
            quadrant.context.fillRect(0, 0, quadrant.canvas.width, quadrant.canvas.height);
        }

        for(i = group_names.length - 1; i >= 0; i -= 1) {
            group = quadrant.things[group_names[i]];

            for(j = 0; j < group.length; j += 1) {
                self.drawThingOnQuadrant(group[j], quadrant);
            }
        }

        quadrant.changed = false;
    };

    /**
     * General function to draw a Thing to a context
     * This will call drawThingOnContext[Single/Multiple] with more arguments
     *
     * @return {Self}
     */
    // self.drawThingOnContext = function(context, thing) {
    self.drawThingOnContext = function(context, thing) {
        if(
            thing.hidden
            || thing.top > MapScreener.bottom
            || thing.right < MapScreener.left
            || thing.bottom < MapScreener.top
            || thing.left > MapScreener.right
        ) {
            return;
        }

        // If there's just one sprite, it's pretty simple
        if(thing.num_sprites === 1) {
            return drawThingOnContextSingle(context, thing.canvas, thing, thing.left, thing.top);
        }
        // For multiple sprites, some calculations will be needed
        else {
            return drawThingOnContextMultiple(context, thing.canvases, thing, thing.left, thing.top);
        }
    }

    /**
     *
     */
    self.drawThingOnQuadrant = function (thing, quadrant) {
        if(thing.hidden) {
            return;
        }

        // If there's just one sprite, it's pretty simple
        if(thing.num_sprites === 1) {
            return drawThingOnContextSingle(quadrant.context, thing.canvas, thing, thing.left - quadrant.left, thing.top - quadrant.top);
        }
        // For multiple sprites, some calculations will be needed
        else {
            return drawThingOnContextMultiple(quadrant.context, thing.canvases, thing, thing.left - quadrant.left, thing.top - quadrant.top);
        }
    };

    /**
     * Draws a Thing's single canvas onto a context (called by self.drawThingOnContext).
     *
     * @param {CanvasRenderingContext2D} context
     * @param {Canvas} canvas
     * @param {Thing} thing
     * @param {Number} leftc
     * @param {Number} topc
     * @return {Self}
     * @private
     */
    function drawThingOnContextSingle(context, canvas, thing, leftc, topc) {
        // If the sprite should repeat, use the pattern equivalent
        if(thing.repeat) {
            drawPatternOnCanvas(context, canvas, leftc, topc, thing.unitwidth, thing.unitheight, thing.opacity || 1);
        }
        // Opacities not equal to one must reset the context afterwards
        else if(thing.opacity != 1) {
            context.globalAlpha = thing.opacity;
            context.drawImage(canvas, leftc, topc);
            context.globalAlpha = 1;
        } else {
            context.drawImage(canvas, leftc, topc);
        }

        return self;
    }

    /**
     * Draws a Thing's multiple canvases onto a context (called by self.drawThingOnContext)
     *
     * @return {Self}
     * @private
     */
    function drawThingOnContextMultiple(context, canvases, thing, leftc, topc) {
        var sprite = thing.sprite,
            topreal = topc,
            leftreal = leftc,
            rightreal = leftc + thing.unitwidth,
            bottomreal = topc + thing.unitheight,
            widthreal = thing.unitwidth,
            heightreal = thing.unitheight,
            spritewidthpixels = thing.spritewidthpixels,
            spriteheightpixels = thing.spriteheightpixels,
            opacity = thing.opacity,
            sdiff, canvasref;

        // Vertical sprites may have 'top', 'bottom', 'middle'
        switch(canvases.direction) {
            case "vertical":
                // If there's a bottom, draw that and push up bottomreal
                if((canvasref = canvases.bottom)) {
                    sdiff = sprite.bottomheight || spriteheightpixels;
                    drawPatternOnCanvas(context, canvasref.canvas, leftreal, bottomreal - sdiff, widthreal, Math.min(heightreal, spriteheightpixels), opacity);
                    bottomreal -= sdiff;
                    heightreal -= sdiff;
                }
                // If there's a top, draw that and push down topreal
                if((canvasref = canvases.top)) {
                    sdiff = sprite.topheight || spriteheightpixels;
                    drawPatternOnCanvas(context, canvasref.canvas, leftreal, topreal, widthreal, Math.min(heightreal, spriteheightpixels), opacity);
                    topreal += sdiff;
                    heightreal -= sdiff;
                }
            break;
            // Horizontal sprites may have 'left', 'right', 'middle'
            case "horizontal":
                // If there's a left, draw that and push up leftreal
                if((canvasref = canvases.left)) {
                    sdiff = sprite.leftwidth || spritewidthpixels;
                    drawPatternOnCanvas(context, canvasref.canvas, leftreal, topreal, Math.min(widthreal, spritewidthpixels), heightreal, opacity);
                    leftreal += sdiff;
                    widthreal -= sdiff;
                }
                // If there's a right, draw that and push back rightreal
                if((canvasref = canvases.right)) {
                    sdiff = sprite.rightwidth || spritewidthpixels;
                    drawPatternOnCanvas(context, canvasref.canvas, rightreal - sdiff, topreal, Math.min(widthreal, spritewidthpixels), heightreal, opacity);
                    rightreal -= sdiff;
                    widthreal -= sdiff;
                }
            break;
        }

        // If there's still room/*, and it exists*/, draw the actual canvas
        if((canvasref = canvases.middle) && topreal < bottomreal && leftreal < rightreal) {
            drawPatternOnCanvas(context, canvasref.canvas, leftreal, topreal, widthreal, heightreal, opacity);
        }

        return self;
    }

    /* Utilities
    */

    /**
     * Macro to draw a pattern onto a canvas because of how
     * often it's used by the regular draw functions.
     * Not a fan of this lack of control over pattern source coordinates...
     */
    function drawPatternOnCanvas(context, source, leftc, topc, width, height, opacity) {
        context.globalAlpha = opacity;
        context.translate(leftc, topc);
        context.fillStyle = context.createPattern(source, "repeat");
        context.fillRect(0, 0, width, height);
        context.translate(-leftc, -topc);
        context.globalAlpha = 1;
    }

    self.reset(settings || {});
}<|endoftext|>


<commit_before>/**
 * bitcoinjs-lib backwards compatibility lib
 * exposes some old functions for easily backporting
 */

'use strict';

define(['bitcoinjs-lib-real', 'convert'], function(Bitcoin, Convert) {
    console.log("loading bitcoinjs-lib-real");
    Bitcoin.Address.validate = function(address) {
        try {
            Bitcoin.base58check.decode(address);
            return true;
        } catch (e) {
            return false;
        }
    }
    Bitcoin.Address.fromInputScript = function(script, network) {
      network = network || Bitcoin.networks.bitcoin

      var type = Bitcoin.scripts.classifyInput(script)

      if (type === 'pubkey') {
          var hash = Bitcoin.crypto.hash160(script.chunks[0]);
          return new Bitcoin.Address(hash, network.pubKeyHash);
      }
      if (type === 'pubkeyhash') {
          var hash = Bitcoin.crypto.hash160(script.chunks[1]);
          return new Bitcoin.Address(hash, network.pubKeyHash);
      }
      if (type === 'scripthash') {
          var hash = Bitcoin.crypto.hash160(script.chunks[script.chunks.length-1]);
          return new Bitcoin.Address(hash, network.scriptHash);
      }

      throw Error(type + ' has no matching Address')
    }

    Bitcoin.Address.getVersion = function(address) {
        return Bitcoin.base58check.decode(address).readUInt8(0);
    }

    Bitcoin.ECKey.fromBytes = function(bytes, compressed) {
        if (!bytes) {
            return Bitcoin.ECKey.makeRandom(compressed);
        }
        var d = Bitcoin.BigInteger.fromByteArrayUnsigned(bytes.slice(0, 32));
        if (compressed === null || compressed === undefined) compressed = (bytes[32] === 1);
        return new Bitcoin.ECKey(d, compressed);
    }
    Bitcoin.ECPubKey.fromBytes = function(bytes) {
        return Bitcoin.ECPubKey.fromBuffer(new Bitcoin.Buffer(bytes));
    }
    Bitcoin.ECKey.prototype.toBytes = function() {
         var bytes = this.d.toBuffer().toJSON().data;
         while(bytes.length < 32) bytes.unshift(0);
         if (this.pub.compressed) bytes.push(1);
         return bytes;
    }
    Bitcoin.ECPubKey.prototype.toBytes = function(compressed) {
         if (compressed === undefined) compressed = this.compressed;
         return this.Q.getEncoded(compressed).toJSON().data;
    }
    Bitcoin.convert = Convert;
    return Bitcoin;

});

<commit_msg>Just return undefined if an address can't be decoded.<commit_after>/**
 * bitcoinjs-lib backwards compatibility lib
 * exposes some old functions for easily backporting
 */

'use strict';

define(['bitcoinjs-lib-real', 'convert'], function(Bitcoin, Convert) {
    console.log("loading bitcoinjs-lib-real");
    Bitcoin.Address.validate = function(address) {
        try {
            Bitcoin.base58check.decode(address);
            return true;
        } catch (e) {
            return false;
        }
    }
    Bitcoin.Address.fromInputScript = function(script, network) {
      network = network || Bitcoin.networks.bitcoin

      var type = Bitcoin.scripts.classifyInput(script)

      if (type === 'pubkey') {
          var hash = Bitcoin.crypto.hash160(script.chunks[0]);
          return new Bitcoin.Address(hash, network.pubKeyHash);
      }
      if (type === 'pubkeyhash') {
          var hash = Bitcoin.crypto.hash160(script.chunks[1]);
          return new Bitcoin.Address(hash, network.pubKeyHash);
      }
      if (type === 'scripthash') {
          var hash = Bitcoin.crypto.hash160(script.chunks[script.chunks.length-1]);
          return new Bitcoin.Address(hash, network.scriptHash);
      }

      // throw Error(type + ' has no matching Address')
    }

    Bitcoin.Address.getVersion = function(address) {
        return Bitcoin.base58check.decode(address).readUInt8(0);
    }

    Bitcoin.ECKey.fromBytes = function(bytes, compressed) {
        if (!bytes) {
            return Bitcoin.ECKey.makeRandom(compressed);
        }
        var d = Bitcoin.BigInteger.fromByteArrayUnsigned(bytes.slice(0, 32));
        if (compressed === null || compressed === undefined) compressed = (bytes[32] === 1);
        return new Bitcoin.ECKey(d, compressed);
    }
    Bitcoin.ECPubKey.fromBytes = function(bytes) {
        return Bitcoin.ECPubKey.fromBuffer(new Bitcoin.Buffer(bytes));
    }
    Bitcoin.ECKey.prototype.toBytes = function() {
         var bytes = this.d.toBuffer().toJSON().data;
         while(bytes.length < 32) bytes.unshift(0);
         if (this.pub.compressed) bytes.push(1);
         return bytes;
    }
    Bitcoin.ECPubKey.prototype.toBytes = function(compressed) {
         if (compressed === undefined) compressed = this.compressed;
         return this.Q.getEncoded(compressed).toJSON().data;
    }
    Bitcoin.convert = Convert;
    return Bitcoin;

});

<|endoftext|>


<commit_before>import ms from "ms";
import {createClient} from "redis";

export default class RedisStore {
	constructor(options={}) {
		this.prefix = options.prefix == null ? 'jwt:' : options.prefix;
		delete options.prefix;

		if (options.url) {
			options.socket = options.url;
		}

		// convert to redis connect params
		if (options.client) {
			this.client = options.client;
		}
		else if (options.socket) {
			this.client = createClient(options.socket, options);
		}
		else {
			this.client = createClient(options);
		}

		this.ttl = options.ttl;
		let p = [];

		if (options.pass) p.push(new Promise((resolve, reject) => {
			this.client.auth(options.pass, e => {
				if (e) reject(e);
				else resolve();
			});
		}));

		if ('db' in options) {
			if (typeof options.db !== 'number') {
				console.error('Warning: redis store expects a number for the "db" option');
			}

			this.client.select(options.db);
			this.client.on('connect', () => {
				this.client.select(options.db);
			});
		}

		p.push(new Promise((resolve, reject) => {
			let onError, onConnect;
			let done = (fn) => {
				return () => {
					this.client.removeListener('error', onError);
					this.client.removeListener('connect', onConnect);
					fn.apply(null, arguments);
				};
			};

			this.client.on('error', onError = done(reject));
			this.client.on('connect', onConnect = done(resolve));
		}));

		this._ready = Promise.all(p);
	}

	load() {
		return this._ready;
	}

	_getKey(sid) {
		return this.prefix + sid;
	}

	add(sid) {
		return new Promise((resolve, reject) => {
			let key = this._getKey(sid);
			let value = Date.now();
			let done = (err) => {
				if (err) reject(err);
				else resolve();
			};

			if (this.ttl) {
				this.client.setex(key, ms(String(this.ttl)), value, done);
			} else {
				this.client.set(key, value, done);
			}
		});
	}

	exists(sid) {
		return new Promise((resolve, reject) => {
			this.client.exists(this._getKey(sid), (err, res) => {
				if (err) reject(err);
				else resolve(res ? true : false);
			});
		});
	}

	remove(sid) {
		return new Promise((resolve, reject) => {
			this.client.del(this._getKey(sid), (err, res) => {
				if (err) reject(err);
				else resolve(res ? true : false);
			});
		});
	}
}
<commit_msg>fix: removed redis store<commit_after><|endoftext|>


<commit_before>import React, { PropTypes as pt } from 'react';
import classNames from 'classnames';

import composeRecipeContainer from './RecipeContainer.js';
import { runRecipe } from '../../selfrepair/self_repair_runner.js';
import NormandyDriver from '../../selfrepair/normandy_driver.js';
import Mozilla from '../../selfrepair/uitour.js';

export class UnwrappedRecipePreview extends React.Component {
  static propTypes = {
    recipe: pt.object.isRequired,
  }

  constructor(props) {
    super(props);

    this.state = {
      status: 'start',
      error: null,
      errorHelp: null,
    };
  }

  componentWillMount() {
    this.attemptPreview();
  }

  componentDidUpdate() {
    this.attemptPreview();
  }

  attemptPreview() {
    const { recipe } = this.props;
    const { status } = this.state;
    const driver = new NormandyDriver();
    driver.registerCallbacks();

    if (recipe && status === 'start') {
      this.pingUITour();
    } else if (recipe && status === 'uitourFound') {
      this.setState({
        status: 'attempting',
      });

      runRecipe(recipe, driver, { testing: true }).then(() => {
        this.setState({
          status: 'executed',
        });
      })
      .catch(error => {
        this.setState({
          status: 'error',
          error: `Error running recipe: ${error}`,
        });
      });
    }
  }

  currentURL() {
    // This is for mocking out in tests
    return new URL(window.location);
  }

  pingUITour() {
    const timeout = setTimeout(() => {
      const url = this.currentURL();
      const prefName = 'browser.uitour.testingOrigins';
      const prefValue = `${url.protocol}//${url.hostname}${url.port ? `:${url.port}` : ''}`;

      this.setState({
        status: 'error',
        error: 'UITour unavailable',
        errorHelp: (

            Make sure the pref {prefName} includes {prefValue}.

        ),
      });
    }, 1000);

    Mozilla.UITour.ping(() => {
      clearTimeout(timeout);
      this.setState({
        status: 'uitourFound',
      });
    });
  }

  render() {
    const { recipe } = this.props;
    const { status, error, errorHelp } = this.state;
    if (recipe) {
      return (

Previewing {recipe.name}...

Action Type: {recipe.action}

            <ExecuteStatus status={status} error={error} errorHelp={errorHelp} />

      );
    }
    return null;
  }
}

function ExecuteStatus({ status, error, errorHelp }) {
  let statusColor = 'grey';
  let statusIcon = 'circle';
  let statusText = 'Unknown';

  switch (status) {
    case 'start':
    case 'uitourFound': {
      statusColor = 'blue';
      statusText = 'Initializing';
      break;
    }
    case 'attempting': {
      statusColor = 'green';
      statusIcon = 'circle-thin';
      statusText = 'Running recipe';
      break;
    }
    case 'executed': {
      statusColor = 'green';
      statusText = 'Recipe executed';
      break;
    }
    case 'error': {
      statusColor = 'red';
      statusIcon = 'circle-thin';
      statusText = {error} {errorHelp &&
{errorHelp}
};
      break;
    }
    default: {
      throw new Error(`Unexpected execution status "${status}"`);
    }
  }

  return (

      <i className={`fa fa-${statusIcon} pre`} />
      {statusText}

  );
}
ExecuteStatus.propTypes = {
  status: pt.string.isRequired,
  error: pt.node,
  errorHelp: pt.node,
};

export default composeRecipeContainer(UnwrappedRecipePreview);
<commit_msg>Avoid creating a new driver in RecipePreview.<commit_after>import React, { PropTypes as pt } from 'react';
import classNames from 'classnames';

import composeRecipeContainer from './RecipeContainer.js';
import { runRecipe } from '../../selfrepair/self_repair_runner.js';
import NormandyDriver from '../../selfrepair/normandy_driver.js';
import Mozilla from '../../selfrepair/uitour.js';

export class UnwrappedRecipePreview extends React.Component {
  static propTypes = {
    recipe: pt.object.isRequired,
  }

  constructor(props) {
    super(props);

    this.state = {
      status: 'start',
      error: null,
      errorHelp: null,
    };

    this.driver = new NormandyDriver();
    this.driver.registerCallbacks();
  }

  componentWillMount() {
    this.attemptPreview();
  }

  componentDidUpdate() {
    this.attemptPreview();
  }

  attemptPreview() {
    const { recipe } = this.props;
    const { status } = this.state;

    if (recipe && status === 'start') {
      this.pingUITour();
    } else if (recipe && status === 'uitourFound') {
      this.setState({
        status: 'attempting',
      });

      runRecipe(recipe, this.driver, { testing: true })
      .then(() => {
        this.setState({
          status: 'executed',
        });
      })
      .catch(error => {
        this.setState({
          status: 'error',
          error: `Error running recipe: ${error}`,
        });
      });
    }
  }

  currentURL() {
    // This is for mocking out in tests
    return new URL(window.location);
  }

  pingUITour() {
    const timeout = setTimeout(() => {
      const url = this.currentURL();
      const prefName = 'browser.uitour.testingOrigins';
      const prefValue = `${url.protocol}//${url.hostname}${url.port ? `:${url.port}` : ''}`;

      this.setState({
        status: 'error',
        error: 'UITour unavailable',
        errorHelp: (

            Make sure the pref {prefName} includes {prefValue}.

        ),
      });
    }, 1000);

    Mozilla.UITour.ping(() => {
      clearTimeout(timeout);
      this.setState({
        status: 'uitourFound',
      });
    });
  }

  render() {
    const { recipe } = this.props;
    const { status, error, errorHelp } = this.state;
    if (recipe) {
      return (

Previewing {recipe.name}...

Action Type: {recipe.action}

            <ExecuteStatus status={status} error={error} errorHelp={errorHelp} />

      );
    }
    return null;
  }
}

function ExecuteStatus({ status, error, errorHelp }) {
  let statusColor = 'grey';
  let statusIcon = 'circle';
  let statusText = 'Unknown';

  switch (status) {
    case 'start':
    case 'uitourFound': {
      statusColor = 'blue';
      statusText = 'Initializing';
      break;
    }
    case 'attempting': {
      statusColor = 'green';
      statusIcon = 'circle-thin';
      statusText = 'Running recipe';
      break;
    }
    case 'executed': {
      statusColor = 'green';
      statusText = 'Recipe executed';
      break;
    }
    case 'error': {
      statusColor = 'red';
      statusIcon = 'circle-thin';
      statusText = {error} {errorHelp &&
{errorHelp}
};
      break;
    }
    default: {
      throw new Error(`Unexpected execution status "${status}"`);
    }
  }

  return (

      <i className={`fa fa-${statusIcon} pre`} />
      {statusText}

  );
}
ExecuteStatus.propTypes = {
  status: pt.string.isRequired,
  error: pt.node,
  errorHelp: pt.node,
};

export default composeRecipeContainer(UnwrappedRecipePreview);
<|endoftext|>