<commit_before>import _ from "underscore";

import { handleActions, combineReducers, AngularResourceProxy, createAction, createThunkAction, momentifyTimestamps } from "metabase/lib/redux";
import { push } from "react-router-redux";

import MetabaseAnalytics from "metabase/lib/analytics";
import { augmentTable } from "metabase/lib/table";
import { loadTableAndForeignKeys } from "metabase/lib/table";
import { isFK } from "metabase/lib/types";

// resource wrappers
const MetabaseApi = new AngularResourceProxy("Metabase", ["db_list", "db_metadata", "db_idfields", "table_update", "field_update"]);
const SegmentApi = new AngularResourceProxy("Segment", ["delete"]);
const MetricApi = new AngularResourceProxy("Metric", ["delete"]);
const Segment = new AngularResourceProxy("Segment", ["get", "create", "update", "delete"]);
const Metric = new AngularResourceProxy("Metric", ["get", "create", "update", "delete"]);
const Metabase = new AngularResourceProxy("Metabase", ["dataset"]);
const Revisions = new AngularResourceProxy("Revisions", ["get"]);

async function loadDatabaseMetadata(databaseId) {
    let databaseMetadata = await MetabaseApi.db_metadata({ 'dbId': databaseId });

    databaseMetadata.tables = await Promise.all(databaseMetadata.tables.map(async (table) => {
        table = await augmentTable(table);
        return table;
    }));

    return databaseMetadata;
}

// initializeMetadata
export const initializeMetadata = createThunkAction("INITIALIZE_METADATA", function(databaseId, tableId) {
    return async function(dispatch, getState) {
        let databases, database;
        try {
            databases = await MetabaseApi.db_list();
        } catch(error) {
            console.log("error fetching databases", error);
        }

        // initialize a database
        if (databases && !_.isEmpty(databases)) {
            let db = databaseId ? _.findWhere(databases, {id: databaseId}) : databases[0];

            database = await loadDatabaseMetadata(db.id);
        }

        if (database) {
            dispatch(fetchDatabaseIdfields(database.id));
        }

        return {
            databases,
            database,
            tableId
        }
    };
});

// fetchDatabaseIdfields
export const fetchDatabaseIdfields = createThunkAction("FETCH_IDFIELDS", function(databaseId) {
    return async function(dispatch, getState) {
        try {
            let idfields = await MetabaseApi.db_idfields({ 'dbId': databaseId });
            return idfields.map(function(field) {
                field.displayName = field.table.display_name + " → " + field.display_name;
                return field;
            });
        } catch (error) {
            console.warn("error getting idfields", databaseId, error);
        }
    };
});

// selectDatabase
export const selectDatabase = createThunkAction("SELECT_DATABASE", function(db) {
    return async function(dispatch, getState) {
        try {
            let database = await loadDatabaseMetadata(db.id);

            dispatch(fetchDatabaseIdfields(db.id));

            // we also want to update our url to match our new state
            dispatch(push('/admin/datamodel/database/'+db.id));

            return database;
        } catch (error) {
            console.log("error fetching tables", db.id, error);
        }
    };
});

// selectTable
export const selectTable = createThunkAction("SELECT_TABLE", function(table) {
    return function(dispatch, getState) {
        // we also want to update our url to match our new state
        dispatch(push('/admin/datamodel/database/'+table.db_id+'/table/'+table.id));

        return table.id;
    };
});

// updateTable
export const updateTable = createThunkAction("UPDATE_TABLE", function(table) {
    return async function(dispatch, getState) {
        try {
            // make sure we don't send all the computed metadata
            let slimTable = { ...table };
            slimTable = _.omit(slimTable, "fields", "fields_lookup", "aggregation_options", "breakout_options", "metrics", "segments");

            let updatedTable = await MetabaseApi.table_update(slimTable);
            _.each(updatedTable, (value, key) => { if (key.charAt(0) !== "$") { updatedTable[key] = value } });

            MetabaseAnalytics.trackEvent("Data Model", "Update Table");

            // TODO: we are not actually using this because the way the react components works actually mutates the original object :(
            return updatedTable;

        } catch (error) {
            console.log("error updating table", error);
            //MetabaseAnalytics.trackEvent("Databases", database.id ? "Update Failed" : "Create Failed", database.engine);
        }
    };
});

// updateField
export const updateField = createThunkAction("UPDATE_FIELD", function(field) {
    return async function(dispatch, getState) {
        const { datamodel: { editingDatabase } } = getState();

        try {
            // make sure we don't send all the computed metadata
            let slimField = { ...field };
            slimField = _.omit(slimField, "operators_lookup", "valid_operators", "values");

            // update the field and strip out angular junk
            let updatedField = await MetabaseApi.field_update(slimField);
            _.each(updatedField, (value, key) => { if (key.charAt(0) !== "$") { updatedField[key] = value } });

            // refresh idfields
            let table = _.findWhere(editingDatabase.tables, {id: updatedField.table_id});
            dispatch(fetchDatabaseIdfields(table.db_id));

            MetabaseAnalytics.trackEvent("Data Model", "Update Field");

            // TODO: we are not actually using this because the way the react components works actually mutates the original object :(
            return updatedField;

        } catch (error) {
            console.log("error updating field", error);
            //MetabaseAnalytics.trackEvent("Databases", database.id ? "Update Failed" : "Create Failed", database.engine);
        }
    };
});

// updateFieldSpecialType
export const updateFieldSpecialType = createThunkAction("UPDATE_FIELD_SPECIAL_TYPE", function(field) {
    return function(dispatch, getState) {

        // If we are changing the field from a FK to something else, we should delete any FKs present
        if (field.target && field.target.id != null && isFK(field.special_type)) {
            // we have something that used to be an FK and is now not an FK
            // clean up after ourselves
            field.target = null;
            field.fk_target_field_id = null;
        }

        // save the field
        dispatch(updateField(field));

        MetabaseAnalytics.trackEvent("Data Model", "Update Field Special-Type", field.special_type);
    };
});

// updateFieldTarget
export const updateFieldTarget = createThunkAction("UPDATE_FIELD_TARGET", function(field) {
    return function(dispatch, getState) {
        // This function notes a change in the target of the target of a foreign key
        dispatch(updateField(field));

        MetabaseAnalytics.trackEvent("Data Model", "Update Field Target");
    };
});

// retireSegment
export const onRetireSegment = createThunkAction("RETIRE_SEGMENT", function(segment) {
    return async function(dispatch, getState) {
        const { datamodel: { editingDatabase } } = getState();

        await SegmentApi.delete(segment);
        MetabaseAnalytics.trackEvent("Data Model", "Retire Segment");

        return await loadDatabaseMetadata(editingDatabase.id);
    };
});

// retireMetric
export const onRetireMetric = createThunkAction("RETIRE_METRIC", function(metric) {
    return async function(dispatch, getState) {
        const { datamodel: { editingDatabase } } = getState();

        await MetricApi.delete(metric);
        MetabaseAnalytics.trackEvent("Data Model", "Retire Metric");

        return await loadDatabaseMetadata(editingDatabase.id);
    };
});

// SEGMENTS

export const GET_SEGMENT = "GET_SEGMENT";
export const CREATE_SEGMENT = "CREATE_SEGMENT";
export const UPDATE_SEGMENT = "UPDATE_SEGMENT";
export const DELETE_SEGMENT = "DELETE_SEGMENT";

export const getSegment    = createAction(GET_SEGMENT, Segment.get);
export const createSegment = createAction(CREATE_SEGMENT, Segment.create);
export const updateSegment = createAction(UPDATE_SEGMENT, Segment.update);
export const deleteSegment = createAction(DELETE_SEGMENT, Segment.delete);

// METRICS

export const GET_METRIC = "GET_METRIC";
export const CREATE_METRIC = "CREATE_METRIC";
export const UPDATE_METRIC = "UPDATE_METRIC";
export const DELETE_METRIC = "DELETE_METRIC";

export const getMetric    = createAction(GET_METRIC, Metric.get);
export const createMetric = createAction(CREATE_METRIC, Metric.create);
export const updateMetric = createAction(UPDATE_METRIC, Metric.update);
export const deleteMetric = createAction(DELETE_METRIC, Metric.delete);

// SEGMENT DETAIL

export const LOAD_TABLE_METADATA = "LOAD_TABLE_METADATA";
export const UPDATE_PREVIEW_SUMMARY = "UPDATE_PREVIEW_SUMMARY";

export const loadTableMetadata = createAction(LOAD_TABLE_METADATA, loadTableAndForeignKeys);
export const updatePreviewSummary = createAction(UPDATE_PREVIEW_SUMMARY, async (query) => {
    let result = await Metabase.dataset(query);
    return result.data.rows[0][0];
});

// REVISION HISTORY

export const FETCH_REVISIONS = "FETCH_REVISIONS";

export const fetchRevisions = createThunkAction(FETCH_REVISIONS, ({ entity, id }) =>
    async (dispatch, getState) => {
        let action;
        switch (entity) {
            case "segment": action = getSegment({ segmentId: id }); break;
            case "metric": action = getMetric({ metricId: id }); break;
        }
        let [object, revisions] = await Promise.all([
            dispatch(action),
            Revisions.get({ entity, id })
        ]);
        await dispatch(loadTableMetadata(object.payload.definition.source_table));
        return { object: object.payload, revisions };
    }
);

// reducers

const databases = handleActions({
    ["INITIALIZE_METADATA"]: { next: (state, { payload }) => payload.databases }
}, []);

const idfields = handleActions({
    ["FETCH_IDFIELDS"]: { next: (state, { payload }) => payload ? payload : state }
}, []);

const editingDatabase = handleActions({
    ["INITIALIZE_METADATA"]: { next: (state, { payload }) => payload.database },
    ["SELECT_DATABASE"]: { next: (state, { payload }) => payload ? payload : state },
    ["RETIRE_SEGMENT"]: { next: (state, { payload }) => payload },
    ["RETIRE_METRIC"]: { next: (state, { payload }) => payload }
}, null);

const editingTable = handleActions({
    ["INITIALIZE_METADATA"]: { next: (state, { payload }) => payload.tableId || null },
    ["SELECT_TABLE"]: { next: (state, { payload }) => payload }
}, null);

const segments = handleActions({
    [GET_SEGMENT]:    { next: (state, { payload }) => ({ ...state, [payload.id]: momentifyTimestamps(payload) }) },
    [CREATE_SEGMENT]: { next: (state, { payload }) => ({ ...state, [payload.id]: momentifyTimestamps(payload) }) },
    [UPDATE_SEGMENT]: { next: (state, { payload }) => ({ ...state, [payload.id]: momentifyTimestamps(payload) }) },
    [DELETE_SEGMENT]: { next: (state, { payload }) => { state = { ...state }; delete state[payload.id]; return state; }}
}, {});

const metrics = handleActions({
    [GET_METRIC]:    { next: (state, { payload }) => ({ ...state, [payload.id]: momentifyTimestamps(payload) }) },
    [CREATE_METRIC]: { next: (state, { payload }) => ({ ...state, [payload.id]: momentifyTimestamps(payload) }) },
    [UPDATE_METRIC]: { next: (state, { payload }) => ({ ...state, [payload.id]: momentifyTimestamps(payload) }) },
    [DELETE_METRIC]: { next: (state, { payload }) => { state = { ...state }; delete state[payload.id]; return state; }}
}, {});

const tableMetadata = handleActions({
    [LOAD_TABLE_METADATA]: {
        next: (state, { payload }) => (payload && payload.table) ? payload.table : null,
        throw: (state, action) => null
    }
}, null);

const previewSummary = handleActions({
    [UPDATE_PREVIEW_SUMMARY]: { next: (state, { payload }) => payload }
}, null);

const revisionObject = handleActions({
    [FETCH_REVISIONS]: { next: (state, { payload: revisionObject }) => revisionObject }
}, null);

export default combineReducers({
    databases,
    idfields,
    editingDatabase,
    editingTable,
    segments,
    metrics,
    tableMetadata,
    previewSummary,
    revisionObject
});
<commit_msg>Fix overeager metadata loading in datamodel<commit_after>import _ from "underscore";

import { handleActions, combineReducers, AngularResourceProxy, createAction, createThunkAction, momentifyTimestamps } from "metabase/lib/redux";
import { push } from "react-router-redux";

import MetabaseAnalytics from "metabase/lib/analytics";
import { augmentTable } from "metabase/lib/table";
import { loadTableAndForeignKeys } from "metabase/lib/table";
import { isFK } from "metabase/lib/types";

// resource wrappers
const MetabaseApi = new AngularResourceProxy("Metabase", ["db_list", "db_metadata", "db_idfields", "table_update", "field_update"]);
const SegmentApi = new AngularResourceProxy("Segment", ["delete"]);
const MetricApi = new AngularResourceProxy("Metric", ["delete"]);
const Segment = new AngularResourceProxy("Segment", ["get", "create", "update", "delete"]);
const Metric = new AngularResourceProxy("Metric", ["get", "create", "update", "delete"]);
const Metabase = new AngularResourceProxy("Metabase", ["dataset"]);
const Revisions = new AngularResourceProxy("Revisions", ["get"]);

function loadDatabaseMetadata(databaseId) {
    return MetabaseApi.db_metadata({ 'dbId': databaseId });
}

// initializeMetadata
export const initializeMetadata = createThunkAction("INITIALIZE_METADATA", function(databaseId, tableId) {
    return async function(dispatch, getState) {
        let databases, database;
        try {
            databases = await MetabaseApi.db_list();
        } catch(error) {
            console.log("error fetching databases", error);
        }

        // initialize a database
        if (databases && !_.isEmpty(databases)) {
            let db = databaseId ? _.findWhere(databases, {id: databaseId}) : databases[0];

            database = await loadDatabaseMetadata(db.id);
        }

        if (database) {
            dispatch(fetchDatabaseIdfields(database.id));
        }

        return {
            databases,
            database,
            tableId
        }
    };
});

// fetchDatabaseIdfields
export const fetchDatabaseIdfields = createThunkAction("FETCH_IDFIELDS", function(databaseId) {
    return async function(dispatch, getState) {
        try {
            let idfields = await MetabaseApi.db_idfields({ 'dbId': databaseId });
            return idfields.map(function(field) {
                field.displayName = field.table.display_name + " → " + field.display_name;
                return field;
            });
        } catch (error) {
            console.warn("error getting idfields", databaseId, error);
        }
    };
});

// selectDatabase
export const selectDatabase = createThunkAction("SELECT_DATABASE", function(db) {
    return async function(dispatch, getState) {
        try {
            let database = await loadDatabaseMetadata(db.id);

            dispatch(fetchDatabaseIdfields(db.id));

            // we also want to update our url to match our new state
            dispatch(push('/admin/datamodel/database/'+db.id));

            return database;
        } catch (error) {
            console.log("error fetching tables", db.id, error);
        }
    };
});

// selectTable
export const selectTable = createThunkAction("SELECT_TABLE", function(table) {
    return function(dispatch, getState) {
        // we also want to update our url to match our new state
        dispatch(push('/admin/datamodel/database/'+table.db_id+'/table/'+table.id));

        return table.id;
    };
});

// updateTable
export const updateTable = createThunkAction("UPDATE_TABLE", function(table) {
    return async function(dispatch, getState) {
        try {
            // make sure we don't send all the computed metadata
            let slimTable = { ...table };
            slimTable = _.omit(slimTable, "fields", "fields_lookup", "aggregation_options", "breakout_options", "metrics", "segments");

            let updatedTable = await MetabaseApi.table_update(slimTable);
            _.each(updatedTable, (value, key) => { if (key.charAt(0) !== "$") { updatedTable[key] = value } });

            MetabaseAnalytics.trackEvent("Data Model", "Update Table");

            // TODO: we are not actually using this because the way the react components works actually mutates the original object :(
            return updatedTable;

        } catch (error) {
            console.log("error updating table", error);
            //MetabaseAnalytics.trackEvent("Databases", database.id ? "Update Failed" : "Create Failed", database.engine);
        }
    };
});

// updateField
export const updateField = createThunkAction("UPDATE_FIELD", function(field) {
    return async function(dispatch, getState) {
        const { datamodel: { editingDatabase } } = getState();

        try {
            // make sure we don't send all the computed metadata
            let slimField = { ...field };
            slimField = _.omit(slimField, "operators_lookup", "valid_operators", "values");

            // update the field and strip out angular junk
            let updatedField = await MetabaseApi.field_update(slimField);
            _.each(updatedField, (value, key) => { if (key.charAt(0) !== "$") { updatedField[key] = value } });

            // refresh idfields
            let table = _.findWhere(editingDatabase.tables, {id: updatedField.table_id});
            dispatch(fetchDatabaseIdfields(table.db_id));

            MetabaseAnalytics.trackEvent("Data Model", "Update Field");

            // TODO: we are not actually using this because the way the react components works actually mutates the original object :(
            return updatedField;

        } catch (error) {
            console.log("error updating field", error);
            //MetabaseAnalytics.trackEvent("Databases", database.id ? "Update Failed" : "Create Failed", database.engine);
        }
    };
});

// updateFieldSpecialType
export const updateFieldSpecialType = createThunkAction("UPDATE_FIELD_SPECIAL_TYPE", function(field) {
    return function(dispatch, getState) {

        // If we are changing the field from a FK to something else, we should delete any FKs present
        if (field.target && field.target.id != null && isFK(field.special_type)) {
            // we have something that used to be an FK and is now not an FK
            // clean up after ourselves
            field.target = null;
            field.fk_target_field_id = null;
        }

        // save the field
        dispatch(updateField(field));

        MetabaseAnalytics.trackEvent("Data Model", "Update Field Special-Type", field.special_type);
    };
});

// updateFieldTarget
export const updateFieldTarget = createThunkAction("UPDATE_FIELD_TARGET", function(field) {
    return function(dispatch, getState) {
        // This function notes a change in the target of the target of a foreign key
        dispatch(updateField(field));

        MetabaseAnalytics.trackEvent("Data Model", "Update Field Target");
    };
});

// retireSegment
export const onRetireSegment = createThunkAction("RETIRE_SEGMENT", function(segment) {
    return async function(dispatch, getState) {
        const { datamodel: { editingDatabase } } = getState();

        await SegmentApi.delete(segment);
        MetabaseAnalytics.trackEvent("Data Model", "Retire Segment");

        return await loadDatabaseMetadata(editingDatabase.id);
    };
});

// retireMetric
export const onRetireMetric = createThunkAction("RETIRE_METRIC", function(metric) {
    return async function(dispatch, getState) {
        const { datamodel: { editingDatabase } } = getState();

        await MetricApi.delete(metric);
        MetabaseAnalytics.trackEvent("Data Model", "Retire Metric");

        return await loadDatabaseMetadata(editingDatabase.id);
    };
});

// SEGMENTS

export const GET_SEGMENT = "GET_SEGMENT";
export const CREATE_SEGMENT = "CREATE_SEGMENT";
export const UPDATE_SEGMENT = "UPDATE_SEGMENT";
export const DELETE_SEGMENT = "DELETE_SEGMENT";

export const getSegment    = createAction(GET_SEGMENT, Segment.get);
export const createSegment = createAction(CREATE_SEGMENT, Segment.create);
export const updateSegment = createAction(UPDATE_SEGMENT, Segment.update);
export const deleteSegment = createAction(DELETE_SEGMENT, Segment.delete);

// METRICS

export const GET_METRIC = "GET_METRIC";
export const CREATE_METRIC = "CREATE_METRIC";
export const UPDATE_METRIC = "UPDATE_METRIC";
export const DELETE_METRIC = "DELETE_METRIC";

export const getMetric    = createAction(GET_METRIC, Metric.get);
export const createMetric = createAction(CREATE_METRIC, Metric.create);
export const updateMetric = createAction(UPDATE_METRIC, Metric.update);
export const deleteMetric = createAction(DELETE_METRIC, Metric.delete);

// SEGMENT DETAIL

export const LOAD_TABLE_METADATA = "LOAD_TABLE_METADATA";
export const UPDATE_PREVIEW_SUMMARY = "UPDATE_PREVIEW_SUMMARY";

export const loadTableMetadata = createAction(LOAD_TABLE_METADATA, loadTableAndForeignKeys);
export const updatePreviewSummary = createAction(UPDATE_PREVIEW_SUMMARY, async (query) => {
    let result = await Metabase.dataset(query);
    return result.data.rows[0][0];
});

// REVISION HISTORY

export const FETCH_REVISIONS = "FETCH_REVISIONS";

export const fetchRevisions = createThunkAction(FETCH_REVISIONS, ({ entity, id }) =>
    async (dispatch, getState) => {
        let action;
        switch (entity) {
            case "segment": action = getSegment({ segmentId: id }); break;
            case "metric": action = getMetric({ metricId: id }); break;
        }
        let [object, revisions] = await Promise.all([
            dispatch(action),
            Revisions.get({ entity, id })
        ]);
        await dispatch(loadTableMetadata(object.payload.definition.source_table));
        return { object: object.payload, revisions };
    }
);

// reducers

const databases = handleActions({
    ["INITIALIZE_METADATA"]: { next: (state, { payload }) => payload.databases }
}, []);

const idfields = handleActions({
    ["FETCH_IDFIELDS"]: { next: (state, { payload }) => payload ? payload : state }
}, []);

const editingDatabase = handleActions({
    ["INITIALIZE_METADATA"]: { next: (state, { payload }) => payload.database },
    ["SELECT_DATABASE"]: { next: (state, { payload }) => payload ? payload : state },
    ["RETIRE_SEGMENT"]: { next: (state, { payload }) => payload },
    ["RETIRE_METRIC"]: { next: (state, { payload }) => payload }
}, null);

const editingTable = handleActions({
    ["INITIALIZE_METADATA"]: { next: (state, { payload }) => payload.tableId || null },
    ["SELECT_TABLE"]: { next: (state, { payload }) => payload }
}, null);

const segments = handleActions({
    [GET_SEGMENT]:    { next: (state, { payload }) => ({ ...state, [payload.id]: momentifyTimestamps(payload) }) },
    [CREATE_SEGMENT]: { next: (state, { payload }) => ({ ...state, [payload.id]: momentifyTimestamps(payload) }) },
    [UPDATE_SEGMENT]: { next: (state, { payload }) => ({ ...state, [payload.id]: momentifyTimestamps(payload) }) },
    [DELETE_SEGMENT]: { next: (state, { payload }) => { state = { ...state }; delete state[payload.id]; return state; }}
}, {});

const metrics = handleActions({
    [GET_METRIC]:    { next: (state, { payload }) => ({ ...state, [payload.id]: momentifyTimestamps(payload) }) },
    [CREATE_METRIC]: { next: (state, { payload }) => ({ ...state, [payload.id]: momentifyTimestamps(payload) }) },
    [UPDATE_METRIC]: { next: (state, { payload }) => ({ ...state, [payload.id]: momentifyTimestamps(payload) }) },
    [DELETE_METRIC]: { next: (state, { payload }) => { state = { ...state }; delete state[payload.id]; return state; }}
}, {});

const tableMetadata = handleActions({
    [LOAD_TABLE_METADATA]: {
        next: (state, { payload }) => (payload && payload.table) ? payload.table : null,
        throw: (state, action) => null
    }
}, null);

const previewSummary = handleActions({
    [UPDATE_PREVIEW_SUMMARY]: { next: (state, { payload }) => payload }
}, null);

const revisionObject = handleActions({
    [FETCH_REVISIONS]: { next: (state, { payload: revisionObject }) => revisionObject }
}, null);

export default combineReducers({
    databases,
    idfields,
    editingDatabase,
    editingTable,
    segments,
    metrics,
    tableMetadata,
    previewSummary,
    revisionObject
});
<|endoftext|>


<commit_before>var delta = require('delta')
var abend = require('abend')
var cadence = require('cadence')
var Destructor = require('destructible')
var stream = require('stream')
var coalesce = require('nascent.coalesce')
var Signal = require('signal')
var Procession = require('procession')
var assert = require('assert')
var Requester = require('conduit/requester')
var Responder = require('conduit/responder')
var Server = require('conduit/server')
var Client = require('conduit/client')
var Conduit = require('conduit')
var http = require('http')
var url = require('url')
var logger = require('prolific.logger').createLogger('compassion.colleague')

function Conference (colleague) {
    this._colleague = colleague
}

Colleague.prototype.enqueue = cadence(function (async, envelope) {
    if (envelope == null) {
        return
    }
    this.chatter.push(envelope)
    switch (envelope.method) {
    case 'boundary':
    case 'record':
    case 'replay':
        // For these cases, it was enough to record them.
        break
    case 'response':
        this.responses.push(response)
        break
    case 'naturalized':
        this._kibitzer.naturalize()
        break
    case 'broadcast':
    case 'reduce':
        this._kibitzer.publish(envelope)
        break
    }
})

Conference.prototype.request = function (envelope, callback) {
    this._colleague._request(envelope, callback)
}

function Colleague (ua, kibitzer) {
    this._ua = ua
    this._kibitzer = kibitzer

    this.read = new Procession
    this.write = new Procession
//    this.read.pump(function (envelope) { console.log('READ', envelope) })
//    this.write.pump(function (envelope) { console.log('WRITE', envelope) })

    this._requester = new Requester('colleague', this.read, this.write)
//    this._requester.read.pump(function (envelope) { console.log('REQUESTER READ', envelope) })
    var responder = new Responder(this, 'colleague', this._requester.read, this._requester.write)
    var server = new Server({ object: this, method: '_connect' }, 'outgoing', responder.read, responder.write)
    this._client = new Client('incoming', server.read, server.write)

    this._write = this._client.write

    server.read.pump(this)

    this.connected = new Signal

    this.chatter = new Procession
    this.responses = new Procession

    this.responses.pump(this, '_response')

    this._destructor = new Destructor
    this._destructor.markDestroyed(this, 'destroyed')
    this._destructor.addDestructor('connected', { object: this.connected, method: 'unlatch' })

    this.demolition = this._destructor.events
}

Colleague.prototype.listen = cadence(function (async, input, output) {
    this._destructor.async(async, 'conduit')(function () {
        this._conduit = new Conduit(input, output)
        this._destructor.addDestructor('conduit', this._conduit.destroy.bind(this._conduit))
        this.write.pump(this._conduit.write)
        this._conduit.read.pump(this.read)
        this.connected.unlatch()
        this._conduit.listen(async())
    })
    this._destructor.async(async, 'log')(function () {
        var shifter = this._kibitzer.islander.log.shifter()
        this._destructor.addDestructor('log', shifter.destroy.bind(shifter))
        var loop = async(function () {
            shifter.dequeue(async())
        }, function (entry) {
            async(function () {
                this._write.enqueue(entry && {
                    module: 'colleague',
                    method: 'entry',
                    body: entry
                }, async())
            }, function () {
                if (entry == null) {
                    return [ loop.break ]
                }
            })
        })()
    })
})

Colleague.prototype.request = cadence(function (async, envelope) {
    var properties = this._kibitzer.paxos.government.properties[envelope.to]
    async(function () {
        this._ua.fetch({
            url: properties.url
        }, {
            url: './oob',
            post: envelope,
            raise: true
        }, async())
    }, function (body) {
        return [ body ]
    })
})

Colleague.prototype.destroy = function () {
    this._destructor.destroy()
}

Colleague.prototype.getProperties = cadence(function (async) {
    async(function () {
        this._requester.request('colleague', {
            module: 'colleague',
            method: 'properties',
            body: {
                id: this._kibitzer.paxos.id,
                replaying: false
            }
        }, async())
    }, function (properties) {
        return [ properties ]
    })
})

Colleague.prototype.outOfBand = cadence(function (async, request) {
    async(function () {
        this._requester.request('colleague', {
            module: 'colleague',
            method: request.method,
            from: coalesce(request.from),
            body: request.body
        }, async())
    }, function (response) {
        return [ response ]
    })
})

Colleague.prototype._tunnel = function (tunnel, header) {
    var socket = this._client.connect(header.body)
    tunnel.read.pump(socket.write)
    socket.read.pump(tunnel.write)
}

Colleague.prototype._socket = cadence(function (async, socket, header) {
    var location = url.parse(url.resolve(header.to.url, 'socket'))
    var through = new stream.PassThrough
    var request = http.request({
        host: location.hostname,
        port: +coalesce(location.port, 80),
        method: 'POST',
        path: location.pathname,
        timeout: 5000
    })
    async(function () {
        delta(async()).ee(request).on('response')
    }, function (response) {
        response.pipe(through)
    })
    var conduit = new Conduit(through, request)
    var client = new Client('tunnel', conduit.read, conduit.write)
    var tunnel = client.connect({
        module: 'compassion',
        method: 'tunnel',
        body: header.body
    })
    tunnel.read.pump(function (envelope) {
        if (envelope == null) {
            conduit.destroy()
        }
    })
    socket.read.pump(tunnel.write)
    tunnel.wrote.pump(function (envelope) {
        if (envelope == null) {
            setImmediate(function () { request.end() })
            return
            conduit.write.push(null)
        }
    })
    conduit.wrote.pump(function (envelope) {
        if (envelope == null) {
            request.end()
        }
    })
    tunnel.read.pump(socket.write)
    conduit.listen(abend)
})

Colleague.prototype._connect = function (socket, header) {
    this._socket(socket, header, abend)
}

module.exports = Colleague
<commit_msg>Procession pump needs to be explicit.<commit_after>var delta = require('delta')
var abend = require('abend')
var cadence = require('cadence')
var Destructor = require('destructible')
var stream = require('stream')
var coalesce = require('nascent.coalesce')
var Signal = require('signal')
var Procession = require('procession')
var assert = require('assert')
var Requester = require('conduit/requester')
var Responder = require('conduit/responder')
var Server = require('conduit/server')
var Client = require('conduit/client')
var Conduit = require('conduit')
var http = require('http')
var url = require('url')
var logger = require('prolific.logger').createLogger('compassion.colleague')

function Conference (colleague) {
    this._colleague = colleague
}

Colleague.prototype._read = cadence(function (async, envelope) {
    if (envelope == null) {
        return
    }
    this.chatter.push(envelope)
    switch (envelope.method) {
    case 'boundary':
    case 'record':
    case 'replay':
        // For these cases, it was enough to record them.
        break
    case 'response':
        this.responses.push(response)
        break
    case 'naturalized':
        this._kibitzer.naturalize()
        break
    case 'broadcast':
    case 'reduce':
        this._kibitzer.publish(envelope)
        break
    }
})

Conference.prototype.request = function (envelope, callback) {
    this._colleague._request(envelope, callback)
}

function Colleague (ua, kibitzer) {
    this._ua = ua
    this._kibitzer = kibitzer

    this.read = new Procession
    this.write = new Procession
//    this.read.pump(function (envelope) { console.log('READ', envelope) })
//    this.write.pump(function (envelope) { console.log('WRITE', envelope) })

    this._requester = new Requester('colleague', this.read, this.write)
//    this._requester.read.pump(function (envelope) { console.log('REQUESTER READ', envelope) })
    var responder = new Responder(this, 'colleague', this._requester.read, this._requester.write)
    var server = new Server({ object: this, method: '_connect' }, 'outgoing', responder.read, responder.write)
    this._client = new Client('incoming', server.read, server.write)

    this._write = this._client.write

    server.read.pump(this, '_read')

    this.connected = new Signal

    this.chatter = new Procession
    this.responses = new Procession

    this.responses.pump(this, '_response')

    this._destructor = new Destructor
    this._destructor.markDestroyed(this, 'destroyed')
    this._destructor.addDestructor('connected', { object: this.connected, method: 'unlatch' })

    this.demolition = this._destructor.events
}

Colleague.prototype.listen = cadence(function (async, input, output) {
    this._destructor.async(async, 'conduit')(function () {
        this._conduit = new Conduit(input, output)
        this._destructor.addDestructor('conduit', this._conduit.destroy.bind(this._conduit))
        this.write.pump(this._conduit.write)
        this._conduit.read.pump(this.read)
        this.connected.unlatch()
        this._conduit.listen(async())
    })
    this._destructor.async(async, 'log')(function () {
        var shifter = this._kibitzer.islander.log.shifter()
        this._destructor.addDestructor('log', shifter.destroy.bind(shifter))
        var loop = async(function () {
            shifter.dequeue(async())
        }, function (entry) {
            async(function () {
                this._write.enqueue(entry && {
                    module: 'colleague',
                    method: 'entry',
                    body: entry
                }, async())
            }, function () {
                if (entry == null) {
                    return [ loop.break ]
                }
            })
        })()
    })
})

Colleague.prototype.request = cadence(function (async, envelope) {
    var properties = this._kibitzer.paxos.government.properties[envelope.to]
    async(function () {
        this._ua.fetch({
            url: properties.url
        }, {
            url: './oob',
            post: envelope,
            raise: true
        }, async())
    }, function (body) {
        return [ body ]
    })
})

Colleague.prototype.destroy = function () {
    this._destructor.destroy()
}

Colleague.prototype.getProperties = cadence(function (async) {
    async(function () {
        this._requester.request('colleague', {
            module: 'colleague',
            method: 'properties',
            body: {
                id: this._kibitzer.paxos.id,
                replaying: false
            }
        }, async())
    }, function (properties) {
        return [ properties ]
    })
})

Colleague.prototype.outOfBand = cadence(function (async, request) {
    async(function () {
        this._requester.request('colleague', {
            module: 'colleague',
            method: request.method,
            from: coalesce(request.from),
            body: request.body
        }, async())
    }, function (response) {
        return [ response ]
    })
})

Colleague.prototype._tunnel = function (tunnel, header) {
    var socket = this._client.connect(header.body)
    tunnel.read.pump(socket.write)
    socket.read.pump(tunnel.write)
}

Colleague.prototype._socket = cadence(function (async, socket, header) {
    var location = url.parse(url.resolve(header.to.url, 'socket'))
    var through = new stream.PassThrough
    var request = http.request({
        host: location.hostname,
        port: +coalesce(location.port, 80),
        method: 'POST',
        path: location.pathname,
        timeout: 5000
    })
    async(function () {
        delta(async()).ee(request).on('response')
    }, function (response) {
        response.pipe(through)
    })
    var conduit = new Conduit(through, request)
    var client = new Client('tunnel', conduit.read, conduit.write)
    var tunnel = client.connect({
        module: 'compassion',
        method: 'tunnel',
        body: header.body
    })
    tunnel.read.pump(function (envelope) {
        if (envelope == null) {
            conduit.destroy()
        }
    })
    socket.read.pump(tunnel.write)
    tunnel.wrote.pump(function (envelope) {
        if (envelope == null) {
            setImmediate(function () { request.end() })
            return
            conduit.write.push(null)
        }
    })
    conduit.wrote.pump(function (envelope) {
        if (envelope == null) {
            request.end()
        }
    })
    tunnel.read.pump(socket.write)
    conduit.listen(abend)
})

Colleague.prototype._connect = function (socket, header) {
    this._socket(socket, header, abend)
}

module.exports = Colleague
<|endoftext|>


<commit_before>var x1 =0;
var y1 = 0;
var modifier = 1;

function preload() {
  cheese = loadSound("./cheese.mp3");
}

function setup() {
  var myCanvas = createCanvas(600, 400, WEBGL);
  myCanvas.parent("myContainer");
  cheese.play();
  fft = new p5.fft();
}

function draw() {

var spectrum = fft.analyze();

if (x1 > 1000) {modifier = -2}
else if (x1 < 1) {modifier = 2}
      x1= x1+modifier;
      y1= y1+modifier;

 rotateX(frameCount * 0.01);
 rotateY(frameCount * 1.00);

  box(x1, y1, 200);

  translate(-150,0,0);
  sphere(spectrum.getEnergy("treble"),6);
  translate(150,0,0);
  sphere(spectrum.getEnergy("treble"),6);
  torus(spectrum.getEnergy("bass"), ("lowMid"), 5);

}
<commit_msg>Update sketch.js<commit_after>var x1 =0;
var y1 = 0;
var modifier = 1;

function preload() {
  cheese = loadSound("./cheese.mp3");
}

function setup() {
  var myCanvas = createCanvas(600, 400, WEBGL);
  myCanvas.parent("myContainer");
  cheese.play();
  fft = new p5.FFT();
}

function draw() {

var spectrum = fft.analyze();

if (x1 > 1000) {modifier = -2}
else if (x1 < 1) {modifier = 2}
      x1= x1+modifier;
      y1= y1+modifier;

 rotateX(frameCount * 0.01);
 rotateY(frameCount * 1.00);

  box(x1, y1, 200);

  translate(-150,0,0);
  sphere(spectrum.getEnergy("treble"),6);
  translate(150,0,0);
  sphere(spectrum.getEnergy("treble"),6);
  torus(spectrum.getEnergy("bass"), ("lowMid"), 5);

}
<|endoftext|>


<commit_before>'use strict';

const BaseModel = require('../api/base-model');
const events = require('events');
const process = require('process');
class Sqlite3Model extends BaseModel {

constructor(db, table, schema) {
  super(db, table, schema);
  this.impl.create = this.sqliteCreate;
  this.impl.read = this.sqliteRead;
  this.impl.update = this.sqliteUpdate;
  this.impl.delete = this.sqliteDelete;
  this.impl.list = this.sqliteList;
  const self = this;
  process.nextTick(() => {
    self.emit('ready');
  });
}

sqliteCreate(data) {
  const self = this;
  return new Promise((resolve, reject) => {
    let fields = [];
    let values = [];
    let marks = [];

    for (let f of Object.keys(self.schema)) {
      if (data[f]) {
        fields.push(f);
        values.push(data[f]);
        marks.push('?');
      }
    }
    let sql = `insert into ${self.table} `;
        sql += '(' + fields.join(',') + ')';
        sql += ' values ';
        sql += '(' + marks.join(',') + ')';

    self.db.run(sql, values, function(err, result) {
      if (err) {
        console.log(err);
        reject(err);
        return;
      }
      resolve({
        lastId: this.lastID,
        changes: this.changes
      });
    });
  });
}

sqliteRead(key, filter) {
  const self = this;
  return new Promise((resolve, reject) => {
    let keyField;
    for (let fieldName of (Object.keys(self.schema))) {
      const fieldRecord = self.schema[fieldName];
      if (fieldRecord && fieldRecord.primaryKey) {
        keyField = fieldName;
        break;
      }
    }

    let fields = '*';
    if (filter && Array.isArray(filter)) {
      fields = filter.join(',');
    }

    let sql = `select ${fields} from ${self.table} where ${keyField} = ?`;
    self.db.get(sql, [key], function(err, result) {
      if (err) {
        console.log(err);
        reject(err);
        return;
      }
      resolve(result);
    });
  });
}

sqliteUpdate(key, data) {
  const self = this;
  return new Promise((resolve, reject) => {
    let keyField;
    let fields = [];
    let values = [];
    let marks = [];
    for (let fieldName of (Object.keys(self.schema))) {
      const fieldRecord = self.schema[fieldName];
      if (fieldRecord && fieldRecord.primaryKey) {
        keyField = fieldName;
        break;
      }
    }

    for (let f of Object.keys(self.schema)) {
      if (f !== keyField && data[f]) {
        fields.push(f);
        values.push(data[f]);
        marks.push('?');
      }
    }
    let sql = `replace into ${self.table} `;
        sql += '(' + fields.join(',') + ')';
        sql += ' values ';
        sql += '(' + marks.join(',') + ')';

    self.db.run(sql, values, function(err, result) {
      if (err) {
        console.log(err);
        reject(err);
        return;
      }
      resolve({
        changes: this.changes
      });
    });
  });
}

sqliteDelete(key) {
  const self = this;
  return new Promise((resolve, reject) => {
    let keyField;
    for (let fieldName of (Object.keys(self.schema))) {
      const fieldRecord = self.schema[fieldName];
      if (fieldRecord && fieldRecord.primaryKey) {
        keyField = fieldName;
        break;
      }
    }

    let sql = `delete from ${self.table} where ${keyField} = ?`;
    self.db.run(sql, [key], function(err, result) {
      if (err) {
        console.log(err);
        reject(err);
        return;
      }
      resolve({
        changes: this.changes
      });
    });
  });
}

sqliteList(params) {
  const self = this;
  return new Promise((resolve, reject) => {
    const fields = '*';
    if (params && Array.isArray(params.fields)) {
      fields = params.fields.join(',');
    }
    let filterArgs = '';

    let page = parseInt(params.page || 1);
    let limit = parseInt(params.limit || 10);
    let skip = (page - 1) * limit;
    let args = 'limit ' + skip + ',' + limit;

    let sqlCount = `select count(1) from ${self.table} ${filterArgs}`;
    self.db.get(sqlCount, [], function(err, count) {
      if (err) {
        console.log(err);
        reject(err);
        return;
      }
      let sqlAll = `select ${fields} from ${self.table} ${args}`;
      self.db.all(sqlAll, [], function(err, results) {
        if (err) {
          console.log(err);
          reject(err);
          return;
        }
        resolve({
          data: results,
          totalCount: count['count(1)'],
          page : page,
          totalPages : count['count(1)'] % limit ? parseInt(count['count(1)'] / limit) + 1 : count['count(1)'] / limit,
          limit : limit
        });
      });
    });
  });
}

} // class Sqlite3Model

// Add event emitter capabilities to the class
Object.keys(events.EventEmitter.prototype).forEach((prop) => {
  Sqlite3Model.prototype[prop] = events.EventEmitter.prototype[prop];
})
events.EventEmitter.call(Sqlite3Model);

module.exports = Sqlite3Model;
<commit_msg>Rearrange object for better reading<commit_after>'use strict';

const BaseModel = require('../api/base-model');
const events = require('events');
const process = require('process');
class Sqlite3Model extends BaseModel {

constructor(db, table, schema) {
  super(db, table, schema);
  this.impl.create = this.sqliteCreate;
  this.impl.read = this.sqliteRead;
  this.impl.update = this.sqliteUpdate;
  this.impl.delete = this.sqliteDelete;
  this.impl.list = this.sqliteList;
  const self = this;
  process.nextTick(() => {
    self.emit('ready');
  });
}

sqliteCreate(data) {
  const self = this;
  return new Promise((resolve, reject) => {
    let fields = [];
    let values = [];
    let marks = [];

    for (let f of Object.keys(self.schema)) {
      if (data[f]) {
        fields.push(f);
        values.push(data[f]);
        marks.push('?');
      }
    }
    let sql = `insert into ${self.table} `;
        sql += '(' + fields.join(',') + ')';
        sql += ' values ';
        sql += '(' + marks.join(',') + ')';

    self.db.run(sql, values, function(err, result) {
      if (err) {
        console.log(err);
        reject(err);
        return;
      }
      resolve({
        lastId: this.lastID,
        changes: this.changes
      });
    });
  });
}

sqliteRead(key, filter) {
  const self = this;
  return new Promise((resolve, reject) => {
    let keyField;
    for (let fieldName of (Object.keys(self.schema))) {
      const fieldRecord = self.schema[fieldName];
      if (fieldRecord && fieldRecord.primaryKey) {
        keyField = fieldName;
        break;
      }
    }

    let fields = '*';
    if (filter && Array.isArray(filter)) {
      fields = filter.join(',');
    }

    let sql = `select ${fields} from ${self.table} where ${keyField} = ?`;
    self.db.get(sql, [key], function(err, result) {
      if (err) {
        console.log(err);
        reject(err);
        return;
      }
      resolve(result);
    });
  });
}

sqliteUpdate(key, data) {
  const self = this;
  return new Promise((resolve, reject) => {
    let keyField;
    let fields = [];
    let values = [];
    let marks = [];
    for (let fieldName of (Object.keys(self.schema))) {
      const fieldRecord = self.schema[fieldName];
      if (fieldRecord && fieldRecord.primaryKey) {
        keyField = fieldName;
        break;
      }
    }

    for (let f of Object.keys(self.schema)) {
      if (f !== keyField && data[f]) {
        fields.push(f);
        values.push(data[f]);
        marks.push('?');
      }
    }
    let sql = `replace into ${self.table} `;
        sql += '(' + fields.join(',') + ')';
        sql += ' values ';
        sql += '(' + marks.join(',') + ')';

    self.db.run(sql, values, function(err, result) {
      if (err) {
        console.log(err);
        reject(err);
        return;
      }
      resolve({
        changes: this.changes
      });
    });
  });
}

sqliteDelete(key) {
  const self = this;
  return new Promise((resolve, reject) => {
    let keyField;
    for (let fieldName of (Object.keys(self.schema))) {
      const fieldRecord = self.schema[fieldName];
      if (fieldRecord && fieldRecord.primaryKey) {
        keyField = fieldName;
        break;
      }
    }

    let sql = `delete from ${self.table} where ${keyField} = ?`;
    self.db.run(sql, [key], function(err, result) {
      if (err) {
        console.log(err);
        reject(err);
        return;
      }
      resolve({
        changes: this.changes
      });
    });
  });
}

sqliteList(params) {
  const self = this;
  return new Promise((resolve, reject) => {
    const fields = '*';
    if (params && Array.isArray(params.fields)) {
      fields = params.fields.join(',');
    }
    let filterArgs = '';

    let page = parseInt(params.page || 1);
    let limit = parseInt(params.limit || 10);
    let skip = (page - 1) * limit;
    let args = 'limit ' + skip + ',' + limit;

    let sqlCount = `select count(1) from ${self.table} ${filterArgs}`;
    self.db.get(sqlCount, [], function(err, count) {
      if (err) {
        console.log(err);
        reject(err);
        return;
      }
      let sqlAll = `select ${fields} from ${self.table} ${args}`;
      self.db.all(sqlAll, [], function(err, results) {
        if (err) {
          console.log(err);
          reject(err);
          return;
        }
        resolve({
          data: results,
          totalCount: count['count(1)'],
          totalPages : count['count(1)'] % limit ? parseInt(count['count(1)'] / limit) + 1 : count['count(1)'] / limit,
          page : page,
          limit : limit
        });
      });
    });
  });
}

} // class Sqlite3Model

// Add event emitter capabilities to the class
Object.keys(events.EventEmitter.prototype).forEach((prop) => {
  Sqlite3Model.prototype[prop] = events.EventEmitter.prototype[prop];
})
events.EventEmitter.call(Sqlite3Model);

module.exports = Sqlite3Model;
<|endoftext|>


<commit_before>const resolveUrl = require('resolve-url')
const { Plugin } = require('@uppy/core')
const Translator = require('@uppy/utils/lib/Translator')
const limitPromises = require('@uppy/utils/lib/limitPromises')
const { RequestClient } = require('@uppy/companion-client')
const XHRUpload = require('@uppy/xhr-upload')

function isXml (xhr) {
  const contentType = xhr.headers ? xhr.headers['content-type'] : xhr.getResponseHeader('Content-Type')
  return typeof contentType === 'string' && contentType.toLowerCase() === 'application/xml'
}

function getXmlValue (source, key) {
  const start = source.indexOf(`<${key}>`)
  const end = source.indexOf(`</${key}>`, start)
  return start !== -1 && end !== -1
    ? source.slice(start + key.length + 2, end)
    : ''
}

function assertServerError (res) {
  if (res && res.error) {
    const error = new Error(res.message)
    Object.assign(error, res.error)
    throw error
  }
  return res
}

module.exports = class AwsS3 extends Plugin {
  constructor (uppy, opts) {
    super(uppy, opts)
    this.type = 'uploader'
    this.id = 'AwsS3'
    this.title = 'AWS S3'

    const defaultLocale = {
      strings: {
        preparingUpload: 'Preparing upload...'
      }
    }

    const defaultOptions = {
      timeout: 30 * 1000,
      limit: 0,
      getUploadParameters: this.getUploadParameters.bind(this),
      locale: defaultLocale
    }

    this.opts = { ...defaultOptions, ...opts }

    // i18n
    this.translator = new Translator([ defaultLocale, this.uppy.locale, this.opts.locale ])
    this.i18n = this.translator.translate.bind(this.translator)
    this.i18nArray = this.translator.translateArray.bind(this.translator)

    this.client = new RequestClient(uppy, opts)

    this.prepareUpload = this.prepareUpload.bind(this)

    if (typeof this.opts.limit === 'number' && this.opts.limit !== 0) {
      this.limitRequests = limitPromises(this.opts.limit)
    } else {
      this.limitRequests = (fn) => fn
    }
  }

  getUploadParameters (file) {
    if (!this.opts.serverUrl) {
      throw new Error('Expected a `serverUrl` option containing a Companion address.')
    }

    const filename = encodeURIComponent(file.name)
    const type = encodeURIComponent(file.type)
    return this.client.get(`s3/params?filename=${filename}&type=${type}`)
      .then(assertServerError)
  }

  validateParameters (file, params) {
    const valid = typeof params === 'object' && params &&
      typeof params.url === 'string' &&
      (typeof params.fields === 'object' || params.fields == null) &&
      (params.method == null || /^(put|post)$/i.test(params.method))

    if (!valid) {
      const err = new TypeError(`AwsS3: got incorrect result from 'getUploadParameters()' for file '${file.name}', expected an object '{ url, method, fields, headers }'.\nSee https://uppy.io/docs/aws-s3/#getUploadParameters-file for more on the expected format.`)
      console.error(err)
      throw err
    }

    return params
  }

  prepareUpload (fileIDs) {
    fileIDs.forEach((id) => {
      const file = this.uppy.getFile(id)
      this.uppy.emit('preprocess-progress', file, {
        mode: 'determinate',
        message: this.i18n('preparingUpload'),
        value: 0
      })
    })

    const getUploadParameters = this.limitRequests(this.opts.getUploadParameters)

    return Promise.all(
      fileIDs.map((id) => {
        const file = this.uppy.getFile(id)
        const paramsPromise = Promise.resolve()
          .then(() => getUploadParameters(file))
        return paramsPromise.then((params) => {
          return this.validateParameters(file, params)
        }).then((params) => {
          this.uppy.emit('preprocess-progress', file, {
            mode: 'determinate',
            message: this.i18n('preparingUpload'),
            value: 1
          })
          return params
        }).catch((error) => {
          this.uppy.emit('upload-error', file, error)
        })
      })
    ).then((responses) => {
      const updatedFiles = {}
      fileIDs.forEach((id, index) => {
        const file = this.uppy.getFile(id)
        if (file.error) {
          return
        }

        const {
          method = 'post',
          url,
          fields,
          headers
        } = responses[index]
        const xhrOpts = {
          method,
          formData: method.toLowerCase() === 'post',
          endpoint: url,
          metaFields: Object.keys(fields)
        }

        if (headers) {
          xhrOpts.headers = headers
        }

        const updatedFile = Object.assign({}, file, {
          meta: Object.assign({}, file.meta, fields),
          xhrUpload: xhrOpts
        })

        updatedFiles[id] = updatedFile
      })

      this.uppy.setState({
        files: Object.assign({}, this.uppy.getState().files, updatedFiles)
      })

      fileIDs.forEach((id) => {
        const file = this.uppy.getFile(id)
        this.uppy.emit('preprocess-complete', file)
      })
    })
  }

  install () {
    const { log } = this.uppy
    this.uppy.addPreProcessor(this.prepareUpload)

    let warnedSuccessActionStatus = false
    this.uppy.use(XHRUpload, {
      fieldName: 'file',
      responseUrlFieldName: 'location',
      timeout: this.opts.timeout,
      limit: this.opts.limit,
      responseType: 'text',
      // Get the response data from a successful XMLHttpRequest instance.
      // `content` is the S3 response as a string.
      // `xhr` is the XMLHttpRequest instance.
      getResponseData (content, xhr) {
        const opts = this

        // If no response, we've hopefully done a PUT request to the file
        // in the bucket on its full URL.
        if (!isXml(xhr)) {
          if (opts.method.toUpperCase() === 'POST') {
            if (!warnedSuccessActionStatus) {
              log('[AwsS3] No response data found, make sure to set the success_action_status AWS SDK option to 201. See https://uppy.io/docs/aws-s3/#POST-Uploads', 'warning')
              warnedSuccessActionStatus = true
            }
            // The responseURL won't contain the object key. Give up.
            return { location: null }
          }

          // responseURL is not available in older browsers.
          if (!xhr.responseURL) {
            return { location: null }
          }

          // Trim the query string because it's going to be a bunch of presign
          // parameters for a PUT request—doing a GET request with those will
          // always result in an error
          return { location: xhr.responseURL.replace(/\?.*$/, '') }
        }

        return {
          // Some S3 alternatives do not reply with an absolute URL.
          // Eg DigitalOcean Spaces uses /$bucketName/xyz
          location: resolveUrl(xhr.responseURL, getXmlValue(content, 'Location')),
          bucket: getXmlValue(content, 'Bucket'),
          key: getXmlValue(content, 'Key'),
          etag: getXmlValue(content, 'ETag')
        }
      },

      // Get the error data from a failed XMLHttpRequest instance.
      // `content` is the S3 response as a string.
      // `xhr` is the XMLHttpRequest instance.
      getResponseError (content, xhr) {
        // If no response, we don't have a specific error message, use the default.
        if (!isXml(xhr)) {
          return
        }
        const error = getXmlValue(content, 'Message')
        return new Error(error)
      }
    })
  }

  uninstall () {
    const uploader = this.uppy.getPlugin('XHRUpload')
    this.uppy.removePlugin(uploader)

    this.uppy.removePreProcessor(this.prepareUpload)
  }
}
<commit_msg>s3: Use user provided filename / type for uploaded object, fixes #1238<commit_after>const resolveUrl = require('resolve-url')
const { Plugin } = require('@uppy/core')
const Translator = require('@uppy/utils/lib/Translator')
const limitPromises = require('@uppy/utils/lib/limitPromises')
const { RequestClient } = require('@uppy/companion-client')
const XHRUpload = require('@uppy/xhr-upload')

function isXml (xhr) {
  const contentType = xhr.headers ? xhr.headers['content-type'] : xhr.getResponseHeader('Content-Type')
  return typeof contentType === 'string' && contentType.toLowerCase() === 'application/xml'
}

function getXmlValue (source, key) {
  const start = source.indexOf(`<${key}>`)
  const end = source.indexOf(`</${key}>`, start)
  return start !== -1 && end !== -1
    ? source.slice(start + key.length + 2, end)
    : ''
}

function assertServerError (res) {
  if (res && res.error) {
    const error = new Error(res.message)
    Object.assign(error, res.error)
    throw error
  }
  return res
}

module.exports = class AwsS3 extends Plugin {
  constructor (uppy, opts) {
    super(uppy, opts)
    this.type = 'uploader'
    this.id = 'AwsS3'
    this.title = 'AWS S3'

    const defaultLocale = {
      strings: {
        preparingUpload: 'Preparing upload...'
      }
    }

    const defaultOptions = {
      timeout: 30 * 1000,
      limit: 0,
      getUploadParameters: this.getUploadParameters.bind(this),
      locale: defaultLocale
    }

    this.opts = { ...defaultOptions, ...opts }

    // i18n
    this.translator = new Translator([ defaultLocale, this.uppy.locale, this.opts.locale ])
    this.i18n = this.translator.translate.bind(this.translator)
    this.i18nArray = this.translator.translateArray.bind(this.translator)

    this.client = new RequestClient(uppy, opts)

    this.prepareUpload = this.prepareUpload.bind(this)

    if (typeof this.opts.limit === 'number' && this.opts.limit !== 0) {
      this.limitRequests = limitPromises(this.opts.limit)
    } else {
      this.limitRequests = (fn) => fn
    }
  }

  getUploadParameters (file) {
    if (!this.opts.serverUrl) {
      throw new Error('Expected a `serverUrl` option containing a Companion address.')
    }

    const filename = encodeURIComponent(file.meta.name)
    const type = encodeURIComponent(file.meta.type)
    return this.client.get(`s3/params?filename=${filename}&type=${type}`)
      .then(assertServerError)
  }

  validateParameters (file, params) {
    const valid = typeof params === 'object' && params &&
      typeof params.url === 'string' &&
      (typeof params.fields === 'object' || params.fields == null) &&
      (params.method == null || /^(put|post)$/i.test(params.method))

    if (!valid) {
      const err = new TypeError(`AwsS3: got incorrect result from 'getUploadParameters()' for file '${file.name}', expected an object '{ url, method, fields, headers }'.\nSee https://uppy.io/docs/aws-s3/#getUploadParameters-file for more on the expected format.`)
      console.error(err)
      throw err
    }

    return params
  }

  prepareUpload (fileIDs) {
    fileIDs.forEach((id) => {
      const file = this.uppy.getFile(id)
      this.uppy.emit('preprocess-progress', file, {
        mode: 'determinate',
        message: this.i18n('preparingUpload'),
        value: 0
      })
    })

    const getUploadParameters = this.limitRequests(this.opts.getUploadParameters)

    return Promise.all(
      fileIDs.map((id) => {
        const file = this.uppy.getFile(id)
        const paramsPromise = Promise.resolve()
          .then(() => getUploadParameters(file))
        return paramsPromise.then((params) => {
          return this.validateParameters(file, params)
        }).then((params) => {
          this.uppy.emit('preprocess-progress', file, {
            mode: 'determinate',
            message: this.i18n('preparingUpload'),
            value: 1
          })
          return params
        }).catch((error) => {
          this.uppy.emit('upload-error', file, error)
        })
      })
    ).then((responses) => {
      const updatedFiles = {}
      fileIDs.forEach((id, index) => {
        const file = this.uppy.getFile(id)
        if (file.error) {
          return
        }

        const {
          method = 'post',
          url,
          fields,
          headers
        } = responses[index]
        const xhrOpts = {
          method,
          formData: method.toLowerCase() === 'post',
          endpoint: url,
          metaFields: Object.keys(fields)
        }

        if (headers) {
          xhrOpts.headers = headers
        }

        const updatedFile = Object.assign({}, file, {
          meta: Object.assign({}, file.meta, fields),
          xhrUpload: xhrOpts
        })

        updatedFiles[id] = updatedFile
      })

      this.uppy.setState({
        files: Object.assign({}, this.uppy.getState().files, updatedFiles)
      })

      fileIDs.forEach((id) => {
        const file = this.uppy.getFile(id)
        this.uppy.emit('preprocess-complete', file)
      })
    })
  }

  install () {
    const { log } = this.uppy
    this.uppy.addPreProcessor(this.prepareUpload)

    let warnedSuccessActionStatus = false
    this.uppy.use(XHRUpload, {
      fieldName: 'file',
      responseUrlFieldName: 'location',
      timeout: this.opts.timeout,
      limit: this.opts.limit,
      responseType: 'text',
      // Get the response data from a successful XMLHttpRequest instance.
      // `content` is the S3 response as a string.
      // `xhr` is the XMLHttpRequest instance.
      getResponseData (content, xhr) {
        const opts = this

        // If no response, we've hopefully done a PUT request to the file
        // in the bucket on its full URL.
        if (!isXml(xhr)) {
          if (opts.method.toUpperCase() === 'POST') {
            if (!warnedSuccessActionStatus) {
              log('[AwsS3] No response data found, make sure to set the success_action_status AWS SDK option to 201. See https://uppy.io/docs/aws-s3/#POST-Uploads', 'warning')
              warnedSuccessActionStatus = true
            }
            // The responseURL won't contain the object key. Give up.
            return { location: null }
          }

          // responseURL is not available in older browsers.
          if (!xhr.responseURL) {
            return { location: null }
          }

          // Trim the query string because it's going to be a bunch of presign
          // parameters for a PUT request—doing a GET request with those will
          // always result in an error
          return { location: xhr.responseURL.replace(/\?.*$/, '') }
        }

        return {
          // Some S3 alternatives do not reply with an absolute URL.
          // Eg DigitalOcean Spaces uses /$bucketName/xyz
          location: resolveUrl(xhr.responseURL, getXmlValue(content, 'Location')),
          bucket: getXmlValue(content, 'Bucket'),
          key: getXmlValue(content, 'Key'),
          etag: getXmlValue(content, 'ETag')
        }
      },

      // Get the error data from a failed XMLHttpRequest instance.
      // `content` is the S3 response as a string.
      // `xhr` is the XMLHttpRequest instance.
      getResponseError (content, xhr) {
        // If no response, we don't have a specific error message, use the default.
        if (!isXml(xhr)) {
          return
        }
        const error = getXmlValue(content, 'Message')
        return new Error(error)
      }
    })
  }

  uninstall () {
    const uploader = this.uppy.getPlugin('XHRUpload')
    this.uppy.removePlugin(uploader)

    this.uppy.removePreProcessor(this.prepareUpload)
  }
}
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';

import SPELLS from 'common/SPELLS';

const PRE_INTELLECT_POTION_BUFF = 900;

class RestorationShamanSpreadsheet extends React.Component {
  static propTypes = {
    parser: PropTypes.object.isRequired,
  };

  render() {
    const { parser } = this.props;

    const styles = {
      table: { borderBottom: '1px solid #dddddd', borderTop: '1px solid #dddddd', align: 'right', padding: '20px', float: 'left', margin: '5px', borderCollapse: 'separate', borderSpacing: '10px 0' },
    };

    const getAbility = spellId => parser._modules.abilityTracker.getAbility(spellId);
    const casts = spellId => getAbility(spellId).casts;
    const cpm = spellId => casts(spellId) / (parser.fightDuration / 1000 / 60) >= 0 ? (casts(spellId) / (parser.fightDuration / 1000 / 60)).toFixed(2) : '0';
    const prePotion = parser._modules.prePotion.usedPrePotion ? PRE_INTELLECT_POTION_BUFF : 0;

    return (

Please use the below table to populate the Restoration Shaman Spreadsheet. Link to the sheet

{parser.selectedCombatant._combatantInfo.intellect - prePotion}

{parser.selectedCombatant._combatantInfo.critSpell}

{parser.selectedCombatant._combatantInfo.hasteSpell}

{parser.selectedCombatant._combatantInfo.mastery}

{parser.selectedCombatant._combatantInfo.versatilityHealingDone}

{Math.floor(parser.fightDuration / 1000)}

{parser._modules.statValues.hpsPerIntellect.toFixed(2)}

{parser._modules.statValues.hpsPerCriticalStrike.toFixed(2)}

{parser._modules.statValues.hpsPerHaste.toFixed(2)}

{parser._modules.statValues.hpsPerMastery.toFixed(2)}

{parser._modules.statValues.hpsPerVersatility.toFixed(2)}

{cpm(SPELLS.RIPTIDE.id)}

{cpm(SPELLS.HEALING_RAIN_CAST.id)}

{cpm(SPELLS.HEALING_TIDE_TOTEM_CAST.id)}

{cpm(SPELLS.SPIRIT_LINK_TOTEM.id)}

{parser.selectedCombatant.hasTalent(SPELLS.CLOUDBURST_TOTEM_TALENT.id) ? cpm(SPELLS.CLOUDBURST_TOTEM_TALENT.id) : cpm(SPELLS.HEALING_STREAM_TOTEM_CAST.id)}

{cpm(SPELLS.CHAIN_HEAL.id)}

{parser._modules.spreadsheet.surgingTideProcsPerMinute}

{(parser._modules.spreadsheet.spoutingSpiritsHits / casts(SPELLS.SPIRIT_LINK_TOTEM.id)).toFixed(2)}

{(parser._modules.spreadsheet.overflowingShoresHits / casts(SPELLS.HEALING_RAIN_CAST.id)).toFixed(2)}

{parser._modules.spreadsheet.ebbAndFlowEffectiveness.toFixed(2)}

{parser._modules.combatants.playerCount}

{cpm(SPELLS.ASTRAL_SHIFT.id)}

{(parser.selectedCombatant.getBuffUptime(SPELLS.GHOST_WOLF.id) / 1000).toFixed(2)}

{parser.selectedCombatant.race ? parser.selectedCombatant.race.name : 'Unknown'}

    );
  }
}

export default RestorationShamanSpreadsheet;
<commit_msg>fix NaN if division by 0<commit_after>import React from 'react';
import PropTypes from 'prop-types';

import SPELLS from 'common/SPELLS';

const PRE_INTELLECT_POTION_BUFF = 900;

class RestorationShamanSpreadsheet extends React.Component {
  static propTypes = {
    parser: PropTypes.object.isRequired,
  };

  render() {
    const { parser } = this.props;

    const styles = {
      table: { borderBottom: '1px solid #dddddd', borderTop: '1px solid #dddddd', align: 'right', padding: '20px', float: 'left', margin: '5px', borderCollapse: 'separate', borderSpacing: '10px 0' },
    };

    const getAbility = spellId => parser._modules.abilityTracker.getAbility(spellId);
    const casts = spellId => getAbility(spellId).casts;
    const cpm = spellId => casts(spellId) / (parser.fightDuration / 1000 / 60) >= 0 ? (casts(spellId) / (parser.fightDuration / 1000 / 60)).toFixed(2) : '0';
    const prePotion = parser._modules.prePotion.usedPrePotion ? PRE_INTELLECT_POTION_BUFF : 0;

    return (

Please use the below table to populate the Restoration Shaman Spreadsheet. Link to the sheet

{parser.selectedCombatant._combatantInfo.intellect - prePotion}

{parser.selectedCombatant._combatantInfo.critSpell}

{parser.selectedCombatant._combatantInfo.hasteSpell}

{parser.selectedCombatant._combatantInfo.mastery}

{parser.selectedCombatant._combatantInfo.versatilityHealingDone}

{Math.floor(parser.fightDuration / 1000)}

{parser._modules.statValues.hpsPerIntellect.toFixed(2)}

{parser._modules.statValues.hpsPerCriticalStrike.toFixed(2)}

{parser._modules.statValues.hpsPerHaste.toFixed(2)}

{parser._modules.statValues.hpsPerMastery.toFixed(2)}

{parser._modules.statValues.hpsPerVersatility.toFixed(2)}

{cpm(SPELLS.RIPTIDE.id)}

{cpm(SPELLS.HEALING_RAIN_CAST.id)}

{cpm(SPELLS.HEALING_TIDE_TOTEM_CAST.id)}

{cpm(SPELLS.SPIRIT_LINK_TOTEM.id)}

{parser.selectedCombatant.hasTalent(SPELLS.CLOUDBURST_TOTEM_TALENT.id) ? cpm(SPELLS.CLOUDBURST_TOTEM_TALENT.id) : cpm(SPELLS.HEALING_STREAM_TOTEM_CAST.id)}

{cpm(SPELLS.CHAIN_HEAL.id)}

{parser._modules.spreadsheet.surgingTideProcsPerMinute}

{(parser._modules.spreadsheet.spoutingSpiritsHits / casts(SPELLS.SPIRIT_LINK_TOTEM.id) || 0).toFixed(2)}

{(parser._modules.spreadsheet.overflowingShoresHits / casts(SPELLS.HEALING_RAIN_CAST.id) || 0).toFixed(2)}

{parser._modules.spreadsheet.ebbAndFlowEffectiveness.toFixed(2)}

{parser._modules.combatants.playerCount}

{cpm(SPELLS.ASTRAL_SHIFT.id)}

{(parser.selectedCombatant.getBuffUptime(SPELLS.GHOST_WOLF.id) / 1000).toFixed(2)}

{parser.selectedCombatant.race ? parser.selectedCombatant.race.name : 'Unknown'}

    );
  }
}

export default RestorationShamanSpreadsheet;
<|endoftext|>


<commit_before>/*
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

// see http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/update/nsUpdateService.js

const ID = 'only-minor-update@clear-code.com';

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/ctypes.jsm');
Cu.import('resource://gre/modules/Timer.jsm');

const kCID  = Components.ID('{714fb150-50f3-11e3-8f96-0800200c9a66}');
const kID   = '@clear-code.com/only-minor-update/provider;1';
const kNAME = 'MinorUpdateProviderService';

const CACHE_LIFETIME = 30 * 60 * 1000; // 30min in milliseconds

switch (Services.appinfo.name) {
  case 'Firefox':
    XPCOMUtils.defineLazyServiceGetter(this, 'Application',
      '@mozilla.org/fuel/application;1', 'fuelIApplication');
    break;
  case 'Thunderbird':
    XPCOMUtils.defineLazyServiceGetter(this, 'Application',
      '@mozilla.org/steel/application;1', 'steelIApplication');
    break;
}

function log(aMessage) {
  if (this.Application)
    Application.console.log(aMessage);
  else
    Cu.reportError(new Error(aMessage));
}

XPCOMUtils.defineLazyModuleGetter(this, 'UpdateChannel',
                                  'resource://gre/modules/UpdateChannel.jsm');

XPCOMUtils.defineLazyGetter(this, 'gABI', function() {
  let abi = null;
  try {
    abi = Services.appinfo.XPCOMABI;
  }
  catch(error) {
    Cu.reportError(error);
  }
  if (Services.appinfo.OS == 'Darwin') {
    let macutils = Cc['@mozilla.org/xpcom/mac-utils;1'].
                   getService(Ci.nsIMacUtils);
    if (macutils.isUniversalBinary)
      abi += '-u-' + macutils.architecturesInBinary;
/*
  #ifdef MOZ_SHARK
    // Disambiguate optimised and shark nightlies
    abi += '-shark'
  #endif
*/
  }
  return abi;
});

XPCOMUtils.defineLazyGetter(this, 'gOSVersion', function() {
  let osVersion;
  let sysInfo = Cc['@mozilla.org/system-info;1'].
                getService(Ci.nsIPropertyBag2);
  try {
    osVersion = sysInfo.getProperty('name') + ' ' + sysInfo.getProperty('version');
  }
  catch(error) {
    Cu.reportError(error);
  }

  if (osVersion) {
    if (Services.appinfo.OS == 'WINNT') {
      const BYTE = ctypes.uint8_t;
      const WORD = ctypes.uint16_t;
      const DWORD = ctypes.uint32_t;
      const WCHAR = ctypes.jschar;
      const BOOL = ctypes.int;

      // This structure is described at:
      // http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx
      const SZCSDVERSIONLENGTH = 128;
      const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW',
          [
          {dwOSVersionInfoSize: DWORD},
          {dwMajorVersion: DWORD},
          {dwMinorVersion: DWORD},
          {dwBuildNumber: DWORD},
          {dwPlatformId: DWORD},
          {szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)},
          {wServicePackMajor: WORD},
          {wServicePackMinor: WORD},
          {wSuiteMask: WORD},
          {wProductType: BYTE},
          {wReserved: BYTE}
          ]);

      // This structure is described at:
      // http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx
      const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO',
          [
          {wProcessorArchitecture: WORD},
          {wReserved: WORD},
          {dwPageSize: DWORD},
          {lpMinimumApplicationAddress: ctypes.voidptr_t},
          {lpMaximumApplicationAddress: ctypes.voidptr_t},
          {dwActiveProcessorMask: DWORD.ptr},
          {dwNumberOfProcessors: DWORD},
          {dwProcessorType: DWORD},
          {dwAllocationGranularity: DWORD},
          {wProcessorLevel: WORD},
          {wProcessorRevision: WORD}
          ]);

      let kernel32 = false;
      try {
        kernel32 = ctypes.open('Kernel32');
      } catch(error) {
        Cu.reportError(error);
        osVersion += '.unknown (unknown)';
      }

      if (kernel32) {
        try {
          // Get Service pack info
          try {
            let GetVersionEx = kernel32.declare('GetVersionExW',
                                                ctypes.default_abi,
                                                BOOL,
                                                OSVERSIONINFOEXW.ptr);
            let winVer = OSVERSIONINFOEXW();
            winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size;

            if (0 !== GetVersionEx(winVer.address())) {
              osVersion += '.' + winVer.wServicePackMajor
                        +  '.' + winVer.wServicePackMinor;
            }
            else {
              Cu.reportError(new ERror('gOSVersion - Unknown failure in GetVersionEX (returned 0)'));
              osVersion += '.unknown';
            }
          }
          catch(error) {
            Cu.reportError(error);
            osVersion += '.unknown';
          }

          // Get processor architecture
          let arch = 'unknown';
          try {
            let GetNativeSystemInfo = kernel32.declare('GetNativeSystemInfo',
                                                       ctypes.default_abi,
                                                       ctypes.void_t,
                                                       SYSTEM_INFO.ptr);
            let sysInfo = SYSTEM_INFO();
            // Default to unknown
            sysInfo.wProcessorArchitecture = 0xffff;

            GetNativeSystemInfo(sysInfo.address());
            switch (sysInfo.wProcessorArchitecture) {
              case 9:
                arch = 'x64';
                break;
              case 6:
                arch = 'IA64';
                break;
              case 0:
                arch = 'x86';
                break;
            }
          }
          catch(error) {
            Cu.reportError(error);
          }
          finally {
            osVersion += ' (' + arch + ')';
          }
        } finally {
          kernel32.close();
        }
      }
    }

    try {
      osVersion += ' (' + sysInfo.getProperty('secondaryLibrary') + ')';
    }
    catch(e) {
      // Not all platforms have a secondary widget library, so an error is nothing to worry about.
    }
    osVersion = encodeURIComponent(osVersion);
  }
  return osVersion;
});

function readStringFromInputStream(inputStream) {
  var sis = Cc['@mozilla.org/scriptableinputstream;1'].
            createInstance(Ci.nsIScriptableInputStream);
  sis.init(inputStream);
  var text = sis.read(sis.available());
  sis.close();
  if (text[text.length - 1] == '\n')
    text = text.slice(0, -1);
  return text;
}

var gLocale = null;
function getLocale() {
  if (gLocale)
    return gLocale;

  for each (res in ['app', 'gre']) {
    var channel = Services.io.newChannel('resource://' + res + '/update.locale', null, null);
    try {
      var inputStream = channel.open();
      gLocale = readStringFromInputStream(inputStream);
    } catch(e) {}
    if (gLocale)
      break;
  }

  if (!gLocale)
    throw Components.Exception('update.locale file doesn\'t exist in ' +
                               'either the application or GRE directories',
                               Cr.NS_ERROR_FILE_NOT_FOUND);
  return gLocale;
}

function getDistributionPrefValue(aPrefName) {
  var prefValue = 'default';
  try {
    prefValue = Services.prefs.getDefaultBranch(null).getCharPref(aPrefName);
  }
  catch(error) {
  }
  return prefValue;
}

function MinorUpdateProvider() {
}
MinorUpdateProvider.prototype = {
  observe: function(aSubject, aTopic, aData) {
    switch (aTopic) {
      case 'profile-after-change':
        return this.init();
      case 'update-check-start':
        return this.onUpdate();
    }
  },

  get updateInfoFile() {
    if (!this._updateInfoFile) {
      this._updateInfoFile = Services.dirsvc.get('ProfD', Ci.nsIFile);
      this._updateInfoFile.append('update.xml');
    }
    return this._updateInfoFile;
  },
  _updateInfoFile: null,

  get updateInfoFileURL() {
    if (!this._updateInfoFileURL)
      this._updateInfoFileURL = Services.io.newFileURI(this.updateInfoFile);
    return this._updateInfoFileURL;
  },
  _updateInfoFileURL: null,

  get shouldDownload() {
    if (!this.updateInfoFile.exists())
      return true;

    return Date.now() - this.updateInfoFile.lastModifiedTime >= CACHE_LIFETIME;
  },

  get defaultUpdateURI() {
    if (this._defaultUpdateURI)
      return this._defaultUpdateURI;

    var defaultBranch = Services.prefs.getDefaultBranch(null);
    var uriString = defaultBranch.getComplexValue('app.update.url', Ci.nsISupportsString);

    var spec = uriString.data;
    spec = spec.replace(/%PRODUCT%/g, Services.appinfo.name);
    spec = spec.replace(/%VERSION%/g, Services.appinfo.version);
    spec = spec.replace(/%BUILD_ID%/g, Services.appinfo.appBuildID);
    spec = spec.replace(/%BUILD_TARGET%/g, Services.appinfo.OS + '_' + gABI);
    spec = spec.replace(/%OS_VERSION%/g, gOSVersion);
    if (/%LOCALE%/.test(spec))
      spec = spec.replace(/%LOCALE%/g, getLocale());
    spec = spec.replace(/%CHANNEL%/g, UpdateChannel.get());
    spec = spec.replace(/%PLATFORM_VERSION%/g, Services.appinfo.platformVersion);
    spec = spec.replace(/%DISTRIBUTION%/g,
                        getDistributionPrefValue('distribution.id'));
    spec = spec.replace(/%DISTRIBUTION_VERSION%/g,
                        getDistributionPrefValue('distribution.version'));
    spec = spec.replace(/\+/g, '%2B');

    spec += (spec.indexOf('?') != -1 ? '&' : '?') + 'force=1';

    return this._defaultUpdateURI = Services.io.newURI(spec, 'UTF-8', null);
  },

  init: function() {
    Services.obs.addObserver(this, 'update-check-start', false);
    this.overrideUpdateURL();

    if (this.updateInfoFile.exists())
      this.updateInfoFile.remove(true);
  },

  overrideUpdateURL: function() {
    var updateInfoURL = Services.io.newFileURI(this.updateInfoFile);
    try {
      var current = Services.prefs.getComplexValue('app.update.url.override', Ci.nsISupportsString);
      if (current.data == updateInfoURL.spec)
        return;
    }
    catch(error) {
      Cu.reportError(error);
    }

    var updateInfoURLString = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
    updateInfoURLString.data = updateInfoURL.spec;
    Services.prefs.setComplexValue('app.update.url.override', Ci.nsISupportsString, updateInfoURLString);
  },

  onUpdate: function() {
    log('onUpdate: shouldDownload = ' + this.shouldDownload);
    if (!this.shouldDownload)
      return;

    this.updateCachedUpdateInfo((function() {
      try {
        var currentMajorVersion = Services.appinfo.version.split('.')[0];
        var updateVersion = this.getUpdateVersion();
        log('Trying update: ' + Services.appinfo.version + ' => ' + updateVersion);
        var updateMajorVersion = updateVersion.split('.')[0];
        log('major version: ' + currentMajorVersion + ' => ' + updateMajorVersion);
        if (currentMajorVersion == updateMajorVersion)
          this.retryUpdate();
      }
      catch(error) {
        Cu.reportError(error);
      }
      finally {
        setTimeout((function() {
          this.updateInfoFile.remove(true);
        }).bind(this), 5000);
      }
    }).bind(this));
  },

  updateCachedUpdateInfo: function(aCallback) {
    var source = this.defaultUpdateURI;
    var destination = this.updateInfoFile;
    log('updateCachedUpdateInfo: ' + source.spec + ' => ' + destination.path);
    var self = this;
    var persist = Cc['@mozilla.org/embedding/browser/nsWebBrowserPersist;1']
                   .createInstance(Ci.nsIWebBrowserPersist);
    persist.persistFlags = Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
                           Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
    persist.progressListener = {
      onProgressChange: function(aWebProgress, aRequest,
                                 aCurSelfProgress, aMaxSelfProgress,
                                 aCurTotalProgress, aMaxTotalProgress) {
        var percentage = Math.round((aCurTotalProgress / aMaxTotalProgress) * 100);
        if (percentage < 100)
          return;

        var delay = 100;
        setTimeout(function delayedCallback() {
          if (!self.updateInfoFile.exists()) {
            return setTimeout(delayedCallback, delay);
          }
          aCallback();
        }, delay);
      },
      onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
      }
    };
    persist.saveURI(source, null, null, null, null, destination, null);
  },

  getUpdateVersion: function() {
    var stream = Cc['@mozilla.org/network/file-input-stream;1']
                  .createInstance(Ci.nsIFileInputStream);
    stream.init(this.updateInfoFile, 1, 0, false);
    var updateInfoXMLString = readStringFromInputStream(stream);
    stream.close();

    var DOMParser = Cc['@mozilla.org/xmlextras/domparser;1']
                     .createInstance(Ci.nsIDOMParser);
    var updateInfoXML = DOMParser.parseFromString(updateInfoXMLString, 'text/xml');

    var updates = updateInfoXML.documentElement.childNodes;
    for (let i = 0, maxi = updates.length; i < maxi; i++) {
      let update = updates[i];
      if (update.nodeType != Ci.nsIDOMNode.ELEMENT_NODE)
        continue;
      let version = update.getAttribute('appVersion');
      if (version)
        return version;
    }
    return '';
  },

  retryUpdate: function() {
    var aboutDialog = Services.wm.getMostRecentWindow('Browser:About') ||
                      Services.wm.getMostRecentWindow('Mail:About');
    if (aboutDialog) {
      let opener = aboutDialog.opener;
      let url = aboutDialog.location.href;
      aboutDialog.close();

      let features;
      switch (Services.appinfo.OS) {
        case 'WINNT':
          features = 'chrome,centerscreen,dependent';
          break;
        case 'Darwin':
          features = 'chrome,resizable=no,minimizable=no';
          break;
        default: // Linux
          features = 'chrome,centerscreen,dependent,dialog=no';
          break;
      }
      Services.ww.openDialog(opener, 'chrome://browser/content/aboutDialog.xul', '', features);
    }
    else {
      let US = Cc['@mozilla.org/updates/update-service;1']
                .getService(Ci.nsIApplicationUpdateService);
      US.backgroundChecker.checkForUpdates(US, true);
    }
  },

  classID: kCID,
  contractID: kID,
  classDescription: kNAME,
  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
  _xpcom_categories: [
    { category : 'profile-after-change', service : true }
  ]
};

var NSGetFactory = XPCOMUtils.generateNSGetFactory([MinorUpdateProvider]);
<commit_msg>Reopen about dialog correctly<commit_after>/*
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

// see http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/update/nsUpdateService.js

const ID = 'only-minor-update@clear-code.com';

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/ctypes.jsm');
Cu.import('resource://gre/modules/Timer.jsm');

const kCID  = Components.ID('{714fb150-50f3-11e3-8f96-0800200c9a66}');
const kID   = '@clear-code.com/only-minor-update/provider;1';
const kNAME = 'MinorUpdateProviderService';

const CACHE_LIFETIME = 30 * 60 * 1000; // 30min in milliseconds

switch (Services.appinfo.name) {
  case 'Firefox':
    XPCOMUtils.defineLazyServiceGetter(this, 'Application',
      '@mozilla.org/fuel/application;1', 'fuelIApplication');
    break;
  case 'Thunderbird':
    XPCOMUtils.defineLazyServiceGetter(this, 'Application',
      '@mozilla.org/steel/application;1', 'steelIApplication');
    break;
}

function log(aMessage) {
  if (this.Application)
    Application.console.log(aMessage);
  else
    Cu.reportError(new Error(aMessage));
}

XPCOMUtils.defineLazyModuleGetter(this, 'UpdateChannel',
                                  'resource://gre/modules/UpdateChannel.jsm');

XPCOMUtils.defineLazyGetter(this, 'gABI', function() {
  let abi = null;
  try {
    abi = Services.appinfo.XPCOMABI;
  }
  catch(error) {
    Cu.reportError(error);
  }
  if (Services.appinfo.OS == 'Darwin') {
    let macutils = Cc['@mozilla.org/xpcom/mac-utils;1'].
                   getService(Ci.nsIMacUtils);
    if (macutils.isUniversalBinary)
      abi += '-u-' + macutils.architecturesInBinary;
/*
  #ifdef MOZ_SHARK
    // Disambiguate optimised and shark nightlies
    abi += '-shark'
  #endif
*/
  }
  return abi;
});

XPCOMUtils.defineLazyGetter(this, 'gOSVersion', function() {
  let osVersion;
  let sysInfo = Cc['@mozilla.org/system-info;1'].
                getService(Ci.nsIPropertyBag2);
  try {
    osVersion = sysInfo.getProperty('name') + ' ' + sysInfo.getProperty('version');
  }
  catch(error) {
    Cu.reportError(error);
  }

  if (osVersion) {
    if (Services.appinfo.OS == 'WINNT') {
      const BYTE = ctypes.uint8_t;
      const WORD = ctypes.uint16_t;
      const DWORD = ctypes.uint32_t;
      const WCHAR = ctypes.jschar;
      const BOOL = ctypes.int;

      // This structure is described at:
      // http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx
      const SZCSDVERSIONLENGTH = 128;
      const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW',
          [
          {dwOSVersionInfoSize: DWORD},
          {dwMajorVersion: DWORD},
          {dwMinorVersion: DWORD},
          {dwBuildNumber: DWORD},
          {dwPlatformId: DWORD},
          {szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)},
          {wServicePackMajor: WORD},
          {wServicePackMinor: WORD},
          {wSuiteMask: WORD},
          {wProductType: BYTE},
          {wReserved: BYTE}
          ]);

      // This structure is described at:
      // http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx
      const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO',
          [
          {wProcessorArchitecture: WORD},
          {wReserved: WORD},
          {dwPageSize: DWORD},
          {lpMinimumApplicationAddress: ctypes.voidptr_t},
          {lpMaximumApplicationAddress: ctypes.voidptr_t},
          {dwActiveProcessorMask: DWORD.ptr},
          {dwNumberOfProcessors: DWORD},
          {dwProcessorType: DWORD},
          {dwAllocationGranularity: DWORD},
          {wProcessorLevel: WORD},
          {wProcessorRevision: WORD}
          ]);

      let kernel32 = false;
      try {
        kernel32 = ctypes.open('Kernel32');
      } catch(error) {
        Cu.reportError(error);
        osVersion += '.unknown (unknown)';
      }

      if (kernel32) {
        try {
          // Get Service pack info
          try {
            let GetVersionEx = kernel32.declare('GetVersionExW',
                                                ctypes.default_abi,
                                                BOOL,
                                                OSVERSIONINFOEXW.ptr);
            let winVer = OSVERSIONINFOEXW();
            winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size;

            if (0 !== GetVersionEx(winVer.address())) {
              osVersion += '.' + winVer.wServicePackMajor
                        +  '.' + winVer.wServicePackMinor;
            }
            else {
              Cu.reportError(new ERror('gOSVersion - Unknown failure in GetVersionEX (returned 0)'));
              osVersion += '.unknown';
            }
          }
          catch(error) {
            Cu.reportError(error);
            osVersion += '.unknown';
          }

          // Get processor architecture
          let arch = 'unknown';
          try {
            let GetNativeSystemInfo = kernel32.declare('GetNativeSystemInfo',
                                                       ctypes.default_abi,
                                                       ctypes.void_t,
                                                       SYSTEM_INFO.ptr);
            let sysInfo = SYSTEM_INFO();
            // Default to unknown
            sysInfo.wProcessorArchitecture = 0xffff;

            GetNativeSystemInfo(sysInfo.address());
            switch (sysInfo.wProcessorArchitecture) {
              case 9:
                arch = 'x64';
                break;
              case 6:
                arch = 'IA64';
                break;
              case 0:
                arch = 'x86';
                break;
            }
          }
          catch(error) {
            Cu.reportError(error);
          }
          finally {
            osVersion += ' (' + arch + ')';
          }
        } finally {
          kernel32.close();
        }
      }
    }

    try {
      osVersion += ' (' + sysInfo.getProperty('secondaryLibrary') + ')';
    }
    catch(e) {
      // Not all platforms have a secondary widget library, so an error is nothing to worry about.
    }
    osVersion = encodeURIComponent(osVersion);
  }
  return osVersion;
});

function readStringFromInputStream(inputStream) {
  var sis = Cc['@mozilla.org/scriptableinputstream;1'].
            createInstance(Ci.nsIScriptableInputStream);
  sis.init(inputStream);
  var text = sis.read(sis.available());
  sis.close();
  if (text[text.length - 1] == '\n')
    text = text.slice(0, -1);
  return text;
}

var gLocale = null;
function getLocale() {
  if (gLocale)
    return gLocale;

  for each (res in ['app', 'gre']) {
    var channel = Services.io.newChannel('resource://' + res + '/update.locale', null, null);
    try {
      var inputStream = channel.open();
      gLocale = readStringFromInputStream(inputStream);
    } catch(e) {}
    if (gLocale)
      break;
  }

  if (!gLocale)
    throw Components.Exception('update.locale file doesn\'t exist in ' +
                               'either the application or GRE directories',
                               Cr.NS_ERROR_FILE_NOT_FOUND);
  return gLocale;
}

function getDistributionPrefValue(aPrefName) {
  var prefValue = 'default';
  try {
    prefValue = Services.prefs.getDefaultBranch(null).getCharPref(aPrefName);
  }
  catch(error) {
  }
  return prefValue;
}

function MinorUpdateProvider() {
}
MinorUpdateProvider.prototype = {
  observe: function(aSubject, aTopic, aData) {
    switch (aTopic) {
      case 'profile-after-change':
        return this.init();
      case 'update-check-start':
        return this.onUpdate();
    }
  },

  get updateInfoFile() {
    if (!this._updateInfoFile) {
      this._updateInfoFile = Services.dirsvc.get('ProfD', Ci.nsIFile);
      this._updateInfoFile.append('update.xml');
    }
    return this._updateInfoFile;
  },
  _updateInfoFile: null,

  get updateInfoFileURL() {
    if (!this._updateInfoFileURL)
      this._updateInfoFileURL = Services.io.newFileURI(this.updateInfoFile);
    return this._updateInfoFileURL;
  },
  _updateInfoFileURL: null,

  get shouldDownload() {
    if (!this.updateInfoFile.exists())
      return true;

    return Date.now() - this.updateInfoFile.lastModifiedTime >= CACHE_LIFETIME;
  },

  get defaultUpdateURI() {
    if (this._defaultUpdateURI)
      return this._defaultUpdateURI;

    var defaultBranch = Services.prefs.getDefaultBranch(null);
    var uriString = defaultBranch.getComplexValue('app.update.url', Ci.nsISupportsString);

    var spec = uriString.data;
    spec = spec.replace(/%PRODUCT%/g, Services.appinfo.name);
    spec = spec.replace(/%VERSION%/g, Services.appinfo.version);
    spec = spec.replace(/%BUILD_ID%/g, Services.appinfo.appBuildID);
    spec = spec.replace(/%BUILD_TARGET%/g, Services.appinfo.OS + '_' + gABI);
    spec = spec.replace(/%OS_VERSION%/g, gOSVersion);
    if (/%LOCALE%/.test(spec))
      spec = spec.replace(/%LOCALE%/g, getLocale());
    spec = spec.replace(/%CHANNEL%/g, UpdateChannel.get());
    spec = spec.replace(/%PLATFORM_VERSION%/g, Services.appinfo.platformVersion);
    spec = spec.replace(/%DISTRIBUTION%/g,
                        getDistributionPrefValue('distribution.id'));
    spec = spec.replace(/%DISTRIBUTION_VERSION%/g,
                        getDistributionPrefValue('distribution.version'));
    spec = spec.replace(/\+/g, '%2B');

    spec += (spec.indexOf('?') != -1 ? '&' : '?') + 'force=1';

    return this._defaultUpdateURI = Services.io.newURI(spec, 'UTF-8', null);
  },

  init: function() {
    Services.obs.addObserver(this, 'update-check-start', false);
    this.overrideUpdateURL();

    if (this.updateInfoFile.exists())
      this.updateInfoFile.remove(true);
  },

  overrideUpdateURL: function() {
    var updateInfoURL = Services.io.newFileURI(this.updateInfoFile);
    try {
      var current = Services.prefs.getComplexValue('app.update.url.override', Ci.nsISupportsString);
      if (current.data == updateInfoURL.spec)
        return;
    }
    catch(error) {
      Cu.reportError(error);
    }

    var updateInfoURLString = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
    updateInfoURLString.data = updateInfoURL.spec;
    Services.prefs.setComplexValue('app.update.url.override', Ci.nsISupportsString, updateInfoURLString);
  },

  onUpdate: function() {
    log('onUpdate: shouldDownload = ' + this.shouldDownload);
    if (!this.shouldDownload)
      return;

    this.updateCachedUpdateInfo((function() {
      try {
        var currentMajorVersion = Services.appinfo.version.split('.')[0];
        var updateVersion = this.getUpdateVersion();
        log('Trying update: ' + Services.appinfo.version + ' => ' + updateVersion);
        var updateMajorVersion = updateVersion.split('.')[0];
        log('major version: ' + currentMajorVersion + ' => ' + updateMajorVersion);
        if (currentMajorVersion == updateMajorVersion)
          this.retryUpdate();
      }
      catch(error) {
        Cu.reportError(error);
      }
      finally {
        setTimeout((function() {
          this.updateInfoFile.remove(true);
        }).bind(this), 5000);
      }
    }).bind(this));
  },

  updateCachedUpdateInfo: function(aCallback) {
    var source = this.defaultUpdateURI;
    var destination = this.updateInfoFile;
    log('updateCachedUpdateInfo: ' + source.spec + ' => ' + destination.path);
    var self = this;
    var persist = Cc['@mozilla.org/embedding/browser/nsWebBrowserPersist;1']
                   .createInstance(Ci.nsIWebBrowserPersist);
    persist.persistFlags = Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
                           Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
    persist.progressListener = {
      onProgressChange: function(aWebProgress, aRequest,
                                 aCurSelfProgress, aMaxSelfProgress,
                                 aCurTotalProgress, aMaxTotalProgress) {
        var percentage = Math.round((aCurTotalProgress / aMaxTotalProgress) * 100);
        if (percentage < 100)
          return;

        var delay = 100;
        setTimeout(function delayedCallback() {
          if (!self.updateInfoFile.exists()) {
            return setTimeout(delayedCallback, delay);
          }
          aCallback();
        }, delay);
      },
      onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
      }
    };
    persist.saveURI(source, null, null, null, null, destination, null);
  },

  getUpdateVersion: function() {
    var stream = Cc['@mozilla.org/network/file-input-stream;1']
                  .createInstance(Ci.nsIFileInputStream);
    stream.init(this.updateInfoFile, 1, 0, false);
    var updateInfoXMLString = readStringFromInputStream(stream);
    stream.close();

    var DOMParser = Cc['@mozilla.org/xmlextras/domparser;1']
                     .createInstance(Ci.nsIDOMParser);
    var updateInfoXML = DOMParser.parseFromString(updateInfoXMLString, 'text/xml');

    var updates = updateInfoXML.documentElement.childNodes;
    for (let i = 0, maxi = updates.length; i < maxi; i++) {
      let update = updates[i];
      if (update.nodeType != Ci.nsIDOMNode.ELEMENT_NODE)
        continue;
      let version = update.getAttribute('appVersion');
      if (version)
        return version;
    }
    return '';
  },

  retryUpdate: function() {
    var aboutDialog = Services.wm.getMostRecentWindow('Browser:About') ||
                      Services.wm.getMostRecentWindow('Mail:About');
    if (aboutDialog) {
      let opener = aboutDialog.opener;
      let url = aboutDialog.location.href;
      aboutDialog.close();

      let features;
      switch (Services.appinfo.OS) {
        case 'WINNT':
          features = 'chrome,centerscreen,dependent';
          break;
        case 'Darwin':
          features = 'chrome,resizable=no,minimizable=no';
          break;
        default: // Linux
          features = 'chrome,centerscreen,dependent,dialog=no';
          break;
      }
      Services.ww.openWindow(opener, 'chrome://browser/content/aboutDialog.xul', '', features, null);
    }
    else {
      let US = Cc['@mozilla.org/updates/update-service;1']
                .getService(Ci.nsIApplicationUpdateService);
      US.backgroundChecker.checkForUpdates(US, true);
    }
  },

  classID: kCID,
  contractID: kID,
  classDescription: kNAME,
  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
  _xpcom_categories: [
    { category : 'profile-after-change', service : true }
  ]
};

var NSGetFactory = XPCOMUtils.generateNSGetFactory([MinorUpdateProvider]);
<|endoftext|>