<commit_before>'use strict';

const EventEmitter = require('events').EventEmitter;
const Log          = require('ipfs-log');
const Index        = require('./Index');
const Cache        = require('./Cache');

const DefaultMaxHistory = 256;

class Store {
  constructor(ipfs, id, dbname, options) {
    this.id = id;
    this.dbname = dbname;
    this.events = new EventEmitter();

    if(!options) options = {};
    if(options.Index === undefined) Object.assign(options, { Index: Index });
    if(options.cacheFile === undefined) Object.assign(options, { cacheFile: null });
    if(options.maxHistory === undefined) Object.assign(options, { maxHistory: DefaultMaxHistory });

    this.options = options;
    this._index = new this.options.Index(this.id);
    this._oplog = null;
    this._ipfs = ipfs;
    this._lastWrite = [];
  }

  use() {
    this.events.emit('load', this.dbname);
    this._oplog = new Log(this._ipfs, this.id, this.dbname, this.options);
    return Cache.loadCache(this.options.cacheFile).then(() => {
      const cached = Cache.get(this.dbname);
      if(cached) {
        if(this._lastWrite.indexOf(cached) > -1) this._lastWrite.push(cached);
        return Log.fromIpfsHash(this._ipfs, cached, this.options)
          .then((log) => this._oplog.join(log))
          .then((merged) => this._index.updateIndex(this._oplog, merged))
          .then(() => this.events.emit('ready', this.dbname))
          .then(() => this)
      }

      this.events.emit('ready', this.dbname)
      return Promise.resolve(this);
    });
  }

  close() {
    this.events.emit('close', this.dbname);
  }

  sync(hash) {
    // if(!hash || this._lastWrite.indexOf(hash) > -1) {
    if(!hash) {
      this.events.emit('updated', this.dbname, []);
      return Promise.resolve([]);
    }

    let newItems = [];
    this.events.emit('sync', this.dbname);
    this._lastWrite.push(hash);
    const startTime = new Date().getTime();
    return Log.fromIpfsHash(this._ipfs, hash, this.options)
      .then((log) => this._oplog.join(log))
      .then((merged) => newItems = merged)
      .then(() => Cache.set(this.dbname, hash))
      .then(() => this._index.updateIndex(this._oplog, newItems))
      .then(() => {
        // if(newItems.length > 0) {
        //   console.log("Sync took", (new Date().getTime() - startTime) + "ms", this.id)
        // }
        this.events.emit('updated', this.dbname, newItems);
      })
      .then(() => newItems)
  }

  delete() {
    this._index = new this.options.Index(this.id);
    if(this._oplog)
      this._oplog.clear();
  }

  _addOperation(data) {
    let result, logHash;
    if(this._oplog) {
      return this._oplog.add(data)
        .then((res) => result = res)
        .then(() => Log.getIpfsHash(this._ipfs, this._oplog))
        .then((hash) => logHash = hash)
        .then(() => this._lastWrite.push(logHash))
        .then(() => Cache.set(this.dbname, logHash))
        .then(() => this._index.updateIndex(this._oplog, [result]))
        .then(() => this.events.emit('data', this.dbname, logHash))
        .then(() => result.hash);
    }
  }
}

module.exports = Store;
<commit_msg>Fix performance bottleneck<commit_after>'use strict';

const EventEmitter = require('events').EventEmitter;
const Log          = require('ipfs-log');
const Index        = require('./Index');
const Cache        = require('./Cache');

const DefaultMaxHistory = 256;

class Store {
  constructor(ipfs, id, dbname, options) {
    this.id = id;
    this.dbname = dbname;
    this.events = new EventEmitter();

    if(!options) options = {};
    if(options.Index === undefined) Object.assign(options, { Index: Index });
    if(options.cacheFile === undefined) Object.assign(options, { cacheFile: null });
    if(options.maxHistory === undefined) Object.assign(options, { maxHistory: DefaultMaxHistory });

    this.options = options;
    this._index = new this.options.Index(this.id);
    this._oplog = null;
    this._ipfs = ipfs;
    this._lastWrite = [];
  }

  use() {
    this.events.emit('load', this.dbname);
    this._oplog = new Log(this._ipfs, this.id, this.dbname, this.options);
    return Cache.loadCache(this.options.cacheFile).then(() => {
      const cached = Cache.get(this.dbname);
      if(cached) {
        if(this._lastWrite.indexOf(cached) > -1) this._lastWrite.push(cached);
        return Log.fromIpfsHash(this._ipfs, cached, this.options)
          .then((log) => this._oplog.join(log))
          .then((merged) => this._index.updateIndex(this._oplog, merged))
          .then(() => this.events.emit('ready', this.dbname))
          .then(() => this)
      }

      this.events.emit('ready', this.dbname)
      return Promise.resolve(this);
    });
  }

  close() {
    this.events.emit('close', this.dbname);
  }

  sync(hash) {
    if(!hash || this._lastWrite.indexOf(hash) > -1) {
      this.events.emit('updated', this.dbname, []);
      return Promise.resolve([]);
    }

    let newItems = [];
    this.events.emit('sync', this.dbname);
    this._lastWrite.push(hash);
    const startTime = new Date().getTime();
    return Log.fromIpfsHash(this._ipfs, hash, this.options)
      .then((log) => this._oplog.join(log))
      .then((merged) => newItems = merged)
      .then(() => Cache.set(this.dbname, hash))
      .then(() => this._index.updateIndex(this._oplog, newItems))
      .then(() => {
        // if(newItems.length > 0) {
        //   console.log("Sync took", (new Date().getTime() - startTime) + "ms", this.id)
        // }
        this.events.emit('updated', this.dbname, newItems);
      })
      .then(() => newItems)
  }

  delete() {
    this._index = new this.options.Index(this.id);
    if(this._oplog)
      this._oplog.clear();
  }

  _addOperation(data) {
    let result, logHash;
    if(this._oplog) {
      return this._oplog.add(data)
        .then((res) => result = res)
        .then(() => Log.getIpfsHash(this._ipfs, this._oplog))
        .then((hash) => logHash = hash)
        .then(() => this._lastWrite.push(logHash))
        .then(() => Cache.set(this.dbname, logHash))
        .then(() => this._index.updateIndex(this._oplog, [result]))
        .then(() => this.events.emit('data', this.dbname, logHash))
        .then(() => result.hash);
    }
  }
}

module.exports = Store;
<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash');
const async = require('async');

const EventsBus = require('./libs/EventsBus');
const Logger = require('./libs/Logger');
const Scenario = require('./libs/Scenario');
const Util = require('./libs/Util');

const ScenarioAlreadyRegisteredError = require('./errors/ScenarioAlreadyRegisteredError');
const NoScenariosRegisteredError = require('./errors/NoScenariosRegisteredError');
const ScenarioDoesNotExistError = require('./errors/ScenarioDoesNotExistError');

class Syrup {
    /**
     * Syrup constructor
     */
    constructor() {
        this.scenarios = {};
        this._config = {};
        this._waitingOn = [];
        this._globalsFile = null;
        this._debugging = false;
        this._progress = {};

        EventsBus.listen('syrup:started', (syrup) => {
            this._onProgressUpdate(this._progress);
        });

        EventsBus.listen('scenario:started', (scenario) => {
            this._progress[scenario.name] = 'running';
            this._onProgressUpdate(this._progress);
        });

        EventsBus.listen('scenario:finished', (scenario) => {
            this._progress[scenario.name] = 'finished';
            this._onProgressUpdate(this._progress);
        });

        EventsBus.listen('syrup:finished', (syrup) => {
            this._onPourFinished(syrup._report);
        });
    }

    /**
     *
     * @param configuration
     * @returns {Syrup}
     */
    config(config) {
        this._config = config;

        return this;
    }

    debug() {
        this._debugging = true;

        return this;
    }

    /**
     *
     * @param onProgressUpdate
     * @returns {Syrup}
     */
    progress(onProgressUpdate) {
        this._onProgressUpdate = onProgressUpdate;

        return this;
    }

    /**
     * Placeholder method for progress updates
     *
     * @private
     */
    _onProgressUpdate() {

    }

    /**
     *
     * @param onPourFinished
     * @returns {Syrup}
     */
    report(onPourFinished) {
        this._onPourFinished = onPourFinished;

        return this;
    }

    /**
     * Placeholder method for pour finished
     *
     * @private
     */
    _onPourFinished() {

    }

    /**
     *
     * @param path
     * @returns {Syrup}
     */
    globals(path) {
        this._globalsFile = require('path').resolve(path);

        return this;
    }

    /**
     *
     * @param name
     * @param options
     * @returns {Syrup}
     */
    scenario(name, options) {
        if (this.scenarios[name] !== undefined) {
            throw new ScenarioAlreadyRegisteredError();
        }

        this.scenarios[name] = options;
        this._waitingOn.push(name);

        return this;
    }

    /**
     *
     * @param done
     */
    pour(done) {
        let firstRun = [];

        if (Object.keys(this.scenarios).length === 0) {
            throw new NoScenariosRegisteredError();
        }

        _.each(this.scenarios, (options, name) => {
            this.scenarios[name] = new Scenario(name, Util.deepExtend(options, { globals: this._globalsFile }));
            this.scenarios[name].data = Util.deepExtend(this.scenarios[name].data, this.data);
            this.scenarios[name].config = Util.deepExtend(this.scenarios[name].config, this._config);

            _.each(this.scenarios[name].options.after, (scenario) => {
                if (this.scenarios[scenario] === undefined) {
                    throw new ScenarioDoesNotExistError();
                }
            });

            if(this.scenarios[name].canStart()) {
                firstRun.push(name);
            }
        });

        if (this._debugging) {
            new Logger('syrup');
        }

        EventsBus.emit('syrup:started', { scenarios: _.keys(this.scenarios), config: this._config });

        EventsBus.listen('scenario:finished', (payload) => {
            let index = this._waitingOn.indexOf(payload.name);

            if (
                this._waitingOn.length > 0 &&
                typeof this._waitingOn[index] !== 'undefined'
            ) {
                this._waitingOn.splice(index, 1);
            }

            if (this._waitingOn.length === 0) {
                setTimeout(() => EventsBus.emit('syrup:finished', this));
            }
        });

        async.parallel(_.map(firstRun, (name) => (done) => { this.scenarios[name].start(); done(); }));
    }
}

module.exports = Syrup;
<commit_msg>Simplify calling of scenario:finished methods and clean up<commit_after>'use strict';

const _ = require('lodash');
const async = require('async');

const EventsBus = require('./libs/EventsBus');
const Logger = require('./libs/Logger');
const Scenario = require('./libs/Scenario');
const Util = require('./libs/Util');

const ScenarioAlreadyRegisteredError = require('./errors/ScenarioAlreadyRegisteredError');
const NoScenariosRegisteredError = require('./errors/NoScenariosRegisteredError');
const ScenarioDoesNotExistError = require('./errors/ScenarioDoesNotExistError');

class Syrup {
    /**
     * Syrup constructor
     */
    constructor() {
        this.scenarios = {};
        this._config = {};
        this._waitingOn = [];
        this._globalsFile = null;
        this._debugging = false;
        this._progress = {};

        EventsBus.listen('syrup:started', (syrup) => {
            this._onProgressUpdate(this._progress);
        });

        EventsBus.listen('scenario:started', (scenario) => {
            this._progress[scenario.name] = 'running';
            this._onProgressUpdate(this._progress);
        });

        EventsBus.listen('scenario:finished', (scenario) => {
            this._progress[scenario.name] = 'finished';
            this._onProgressUpdate(this._progress);

            let index = this._waitingOn.indexOf(scenario.name);

            if (
                this._waitingOn.length > 0 &&
                typeof this._waitingOn[index] !== 'undefined'
            ) {
                this._waitingOn.splice(index, 1);
            }

            if (this._waitingOn.length === 0) {
                setTimeout(() => EventsBus.emit('syrup:finished', this));
            }
        });

        EventsBus.listen('syrup:finished', (syrup) => {
            this._onPourFinished(syrup._report);
        });
    }

    /**
     *
     * @param configuration
     * @returns {Syrup}
     */
    config(config) {
        this._config = config;

        return this;
    }

    debug() {
        this._debugging = true;

        return this;
    }

    /**
     *
     * @param onProgressUpdate
     * @returns {Syrup}
     */
    progress(onProgressUpdate) {
        this._onProgressUpdate = onProgressUpdate;

        return this;
    }

    /**
     * Placeholder method for progress updates
     *
     * @private
     */
    _onProgressUpdate() {

    }

    /**
     *
     * @param onPourFinished
     * @returns {Syrup}
     */
    report(onPourFinished) {
        this._onPourFinished = onPourFinished;

        return this;
    }

    /**
     * Placeholder method for pour finished
     *
     * @private
     */
    _onPourFinished() {

    }

    /**
     *
     * @param path
     * @returns {Syrup}
     */
    globals(path) {
        this._globalsFile = require('path').resolve(path);

        return this;
    }

    /**
     *
     * @param name
     * @param options
     * @returns {Syrup}
     */
    scenario(name, options) {
        if (this.scenarios[name] !== undefined) {
            throw new ScenarioAlreadyRegisteredError();
        }

        this.scenarios[name] = options;
        this._waitingOn.push(name);

        return this;
    }

    /**
     *
     * @param done
     */
    pour(done) {
        let firstRun = [];

        if (Object.keys(this.scenarios).length === 0) {
            throw new NoScenariosRegisteredError();
        }

        _.each(this.scenarios, (options, name) => {
            this.scenarios[name] = new Scenario(name, Util.deepExtend(options, { globals: this._globalsFile }));
            this.scenarios[name].data = Util.deepExtend(this.scenarios[name].data, this.data);
            this.scenarios[name].config = Util.deepExtend(this.scenarios[name].config, this._config);
            this._progress[name] = 'pending';

            _.each(this.scenarios[name].options.after, (scenario) => {
                if (this.scenarios[scenario] === undefined) {
                    throw new ScenarioDoesNotExistError();
                }
            });

            if(this.scenarios[name].canStart()) {
                firstRun.push(name);
            }
        });

        if (this._debugging) {
            new Logger('syrup');
        }

        EventsBus.emit('syrup:started', {
            scenarios: _.keys(this.scenarios),
            config: this._config
        });

        async.parallel(_.map(firstRun, (name) => (done) => { this.scenarios[name].start(); done(); }));
    }
}

module.exports = Syrup;
<|endoftext|>


<commit_before>frappe.ui.form.ControlMultiCheck = frappe.ui.form.Control.extend({
	// UI: multiple checkboxes
	// Value: Array of values
	// Options: Array of label/value/checked option objects

	make() {
		this._super();
		this.$label = $(`<label class="control-label">${this.df.label || ''}</label>`).appendTo(this.wrapper);
		this.$load_state = $('
' + __("Loading") + '...
');
		this.$select_buttons = this.get_select_buttons().appendTo(this.wrapper);
		this.$load_state.appendTo(this.wrapper);

		this.$checkbox_area = $('

').appendTo(this.wrapper);
		this.set_options();
		this.bind_checkboxes();
	},

	refresh_input() {
		this.options.map(option => option.value).forEach(value => {
			$(this.wrapper)
				.find(`:checkbox[data-unit="${value}"]`)
				.prop("checked", this.selected_options.includes(value));
		});
	},

	set_options() {
		this.$load_state.show();
		this.$select_buttons.hide();
		this.parse_df_options();

		if(this.df.get_data) {
			if(typeof this.df.get_data().then == 'function') {
				this.df.get_data().then(results => {
					this.options = results;
					this.make_checkboxes();
				});
			} else {
				this.options = this.df.get_data();
				this.make_checkboxes();
			}
		} else {
			this.make_checkboxes();
		}
	},

	parse_df_options() {
		if(Array.isArray(this.df.options)) {
			this.options = this.df.options;
		} else if(this.df.options && this.df.options.length>0 && frappe.utils.is_json(this.df.options)) {
			let args = JSON.parse(this.df.options);
			if(Array.isArray(args)) {
				this.options = args;
			} else if(Array.isArray(args.options)) {
				if(args.select_all) {
					this.select_all = true;
				}
				this.options = args.options;
			}
		} else {
			this.options = [];
		}
	},

	make_checkboxes() {
		this.set_checked_options();
		this.$load_state.hide();
		this.$checkbox_area.empty();
		this.options.forEach(option => {
			this.get_checkbox_element(option).appendTo(this.$checkbox_area);
		});
		if(this.select_all) {
			this.setup_select_all();
		}
	},

	bind_checkboxes() {
		$(this.wrapper).on('change', ':checkbox', e => {
			const $checkbox = $(e.target);
			const option_name = $checkbox.attr("data-unit");
			if($checkbox.is(':checked')) {
				this.selected_options.push(option_name);
			} else {
				let index = this.selected_options.indexOf(option_name);
				this.selected_options.splice(index, 1);
			}
			this.df.on_change && this.df.on_change();
		});
	},

	set_checked_options() {
		this.selected_options = this.options
			.filter(o => o.checked)
			.map(o => o.value);
	},

	setup_select_all() {
		this.$select_buttons.show();
		let select_all = (deselect=false) => {
			$(this.wrapper).find(`:checkbox`).prop("checked", deselect).trigger('click');
		};
		this.$select_buttons.find('.select-all').on('click', () => {
			select_all();
		});
		this.$select_buttons.find('.deselect-all').on('click', () => {
			select_all(true);
		});
	},

	get_value() {
		return this.selected_options;
	},

	get_checked_options() {
		return this.get_value();
	},

	get_unchecked_options() {
		return this.options.map(o => o.value)
			.filter(value => !this.selected_options.includes(value));
	},

	get_checkbox_element(option) {
		const column_size = 12 / (this.df.columns || 1);
		return $(`

				<input type="checkbox" data-unit="${option.value}">
				</input>
				${__(option.label)}

`);
	},

	get_select_buttons() {
		return $(`
<button class="btn btn-xs btn-default select-all">
			${__("Select All")}</button>
			<button class="btn btn-xs btn-default deselect-all">
		${__("Unselect All")}</button>
`);
	}
});
<commit_msg>Multicheck fixes<commit_after>frappe.ui.form.ControlMultiCheck = frappe.ui.form.Control.extend({
	// UI: multiple checkboxes
	// Value: Array of values
	// Options: Array of label/value/checked option objects

	make() {
		this._super();
		this.$label = $(`<label class="control-label">${this.df.label || ''}</label>`).appendTo(this.wrapper);
		this.$load_state = $('
' + __("Loading") + '...
');
		this.$select_buttons = this.get_select_buttons().appendTo(this.wrapper);
		this.$load_state.appendTo(this.wrapper);

		const row = this.get_column_size() === 12 ? '' : 'row';
		this.$checkbox_area = $(`<div class="checkbox-options ${row}"></div>`).appendTo(this.wrapper);
		this.set_options();
		this.bind_checkboxes();
	},

	refresh_input() {
		this.options.map(option => option.value).forEach(value => {
			$(this.wrapper)
				.find(`:checkbox[data-unit="${value}"]`)
				.prop("checked", this.selected_options.includes(value));
		});
	},

	set_options() {
		this.$load_state.show();
		this.$select_buttons.hide();
		this.parse_df_options();

		if(this.df.get_data) {
			if(typeof this.df.get_data().then == 'function') {
				this.df.get_data().then(results => {
					this.options = results;
					this.make_checkboxes();
				});
			} else {
				this.options = this.df.get_data();
				this.make_checkboxes();
			}
		} else {
			this.make_checkboxes();
		}
	},

	parse_df_options() {
		if(Array.isArray(this.df.options)) {
			this.options = this.df.options;
		} else if(this.df.options && this.df.options.length>0 && frappe.utils.is_json(this.df.options)) {
			let args = JSON.parse(this.df.options);
			if(Array.isArray(args)) {
				this.options = args;
			} else if(Array.isArray(args.options)) {
				if(args.select_all) {
					this.select_all = true;
				}
				this.options = args.options;
			}
		} else {
			this.options = [];
		}
	},

	make_checkboxes() {
		this.set_checked_options();
		this.$load_state.hide();
		this.$checkbox_area.empty();
		this.options.forEach(option => {
			this.get_checkbox_element(option).appendTo(this.$checkbox_area);
		});
		if(this.select_all) {
			this.setup_select_all();
		}
	},

	bind_checkboxes() {
		$(this.wrapper).on('change', ':checkbox', e => {
			const $checkbox = $(e.target);
			const option_name = $checkbox.attr("data-unit");
			if($checkbox.is(':checked')) {
				this.selected_options.push(option_name);
			} else {
				let index = this.selected_options.indexOf(option_name);
				this.selected_options.splice(index, 1);
			}
			this.df.on_change && this.df.on_change();
		});
	},

	set_checked_options() {
		this.selected_options = this.options
			.filter(o => o.checked)
			.map(o => o.value);
	},

	setup_select_all() {
		this.$select_buttons.show();
		let select_all = (deselect=false) => {
			$(this.wrapper).find(`:checkbox`).prop("checked", deselect).trigger('click');
		};
		this.$select_buttons.find('.select-all').on('click', () => {
			select_all();
		});
		this.$select_buttons.find('.deselect-all').on('click', () => {
			select_all(true);
		});
	},

	get_value() {
		return this.selected_options;
	},

	get_checked_options() {
		return this.get_value();
	},

	get_unchecked_options() {
		return this.options.map(o => o.value)
			.filter(value => !this.selected_options.includes(value));
	},

	get_checkbox_element(option) {
		const column_size = this.get_column_size();
		return $(`

				<input type="checkbox" data-unit="${option.value}">
				</input>
				${__(option.label)}

`);
	},

	get_select_buttons() {
		return $(`
<button class="btn btn-xs btn-default select-all">
			${__("Select All")}</button>
			<button class="btn btn-xs btn-default deselect-all">
		${__("Unselect All")}</button>
`);
	},

	get_column_size() {
		return 12 / (+this.df.columns || 1);
	}
});
<|endoftext|>


<commit_before>#!/bin/node
import path from 'path';

import {DIST_DIR, KATAS_DIR} from './config';
import {all as rawMetadataEs1} from '../katas/es1/language/__raw-metadata__';
import {all as rawMetadataEs6} from '../katas/es6/language/__raw-metadata__';
import {all as rawMetadataEs8} from '../katas/es8/language/__raw-metadata__';
import {all as rawMetadataEs10} from '../katas/es10/language/__raw-metadata__';
import {all as rawMetadataHamjest} from '../katas/libraries/hamjest/__raw-metadata__';

import {writeToFileAsJson} from './_external-deps/filesystem';
import MetaData from './metadata.js';
import FlatMetaData from './flat-metadata';
import GroupedMetaData from './grouped-metadata';

const destinationDirEs1 = path.join(DIST_DIR, 'katas/es1/language');
const destinationDirEs6 = path.join(DIST_DIR, 'katas/es6/language');
const destinationDirEs8 = path.join(DIST_DIR, 'katas/es8/language');
const destinationDirEs10 = path.join(DIST_DIR, 'katas/es10/language');
const destinationDirHamjest = path.join(DIST_DIR, 'katas/libraries/hamjest');

const buildMetadata = () => {
  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs1, FlatMetaData)
    .writeToFile(path.join(destinationDirEs1, '__all__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs1, GroupedMetaData)
    .writeToFile(path.join(destinationDirEs1, '__grouped__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs6, FlatMetaData)
    .writeToFile(path.join(destinationDirEs6, '__all__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs6, GroupedMetaData)
    .writeToFile(path.join(destinationDirEs6, '__grouped__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs8, FlatMetaData)
    .writeToFile(path.join(destinationDirEs8, '__all__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs8, GroupedMetaData)
    .writeToFile(path.join(destinationDirEs8, '__grouped__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs10, FlatMetaData)
    .writeToFile(path.join(destinationDirEs10, '__all__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs10, GroupedMetaData)
    .writeToFile(path.join(destinationDirEs10, '__grouped__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataHamjest, FlatMetaData)
    .writeToFile(path.join(destinationDirHamjest, '__all__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataHamjest, GroupedMetaData)
    .writeToFile(path.join(destinationDirHamjest, '__grouped__.json'));
};

import {convertTestsToKatas} from './convert-tests-to-katas';
convertTestsToKatas({sourceDir: KATAS_DIR, destinationDir: path.join(DIST_DIR, 'katas')})
  .then(buildMetadata)
;
<commit_msg>Adding ES7 katas fails currently, since they have no publish date, which will be allowed from now on to mark unpublished katas.<commit_after>#!/bin/node
import path from 'path';

import {DIST_DIR, KATAS_DIR} from './config';
import {all as rawMetadataEs1} from '../katas/es1/language/__raw-metadata__';
import {all as rawMetadataEs6} from '../katas/es6/language/__raw-metadata__';
import {all as rawMetadataEs7} from '../katas/es7/language/__raw-metadata__';
import {all as rawMetadataEs8} from '../katas/es8/language/__raw-metadata__';
import {all as rawMetadataEs10} from '../katas/es10/language/__raw-metadata__';
import {all as rawMetadataHamjest} from '../katas/libraries/hamjest/__raw-metadata__';

import {writeToFileAsJson} from './_external-deps/filesystem';
import MetaData from './metadata.js';
import FlatMetaData from './flat-metadata';
import GroupedMetaData from './grouped-metadata';

const destinationDirEs1 = path.join(DIST_DIR, 'katas/es1/language');
const destinationDirEs6 = path.join(DIST_DIR, 'katas/es6/language');
const destinationDirEs7 = path.join(DIST_DIR, 'katas/es7/language');
const destinationDirEs8 = path.join(DIST_DIR, 'katas/es8/language');
const destinationDirEs10 = path.join(DIST_DIR, 'katas/es10/language');
const destinationDirHamjest = path.join(DIST_DIR, 'katas/libraries/hamjest');

const buildMetadata = () => {
  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs1, FlatMetaData)
    .writeToFile(path.join(destinationDirEs1, '__all__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs1, GroupedMetaData)
    .writeToFile(path.join(destinationDirEs1, '__grouped__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs6, FlatMetaData)
    .writeToFile(path.join(destinationDirEs6, '__all__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs6, GroupedMetaData)
    .writeToFile(path.join(destinationDirEs6, '__grouped__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs7, FlatMetaData)
    .writeToFile(path.join(destinationDirEs7, '__all__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs7, GroupedMetaData)
    .writeToFile(path.join(destinationDirEs7, '__grouped__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs8, FlatMetaData)
    .writeToFile(path.join(destinationDirEs8, '__all__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs8, GroupedMetaData)
    .writeToFile(path.join(destinationDirEs8, '__grouped__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs10, FlatMetaData)
    .writeToFile(path.join(destinationDirEs10, '__all__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataEs10, GroupedMetaData)
    .writeToFile(path.join(destinationDirEs10, '__grouped__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataHamjest, FlatMetaData)
    .writeToFile(path.join(destinationDirHamjest, '__all__.json'));

  new MetaData(writeToFileAsJson)
    .convertWith(rawMetadataHamjest, GroupedMetaData)
    .writeToFile(path.join(destinationDirHamjest, '__grouped__.json'));
};

import {convertTestsToKatas} from './convert-tests-to-katas';
convertTestsToKatas({sourceDir: KATAS_DIR, destinationDir: path.join(DIST_DIR, 'katas')})
  .then(buildMetadata)
;
<|endoftext|>


<commit_before>require('babel-polyfill');

import {
  getStudentIdFromStudentNumber,
  getMatchingStudentTest,
  getMatchingStudentTestScore,
  getMatchingProficiency
}
from './service';
import {
  createWriteStream
}
from 'fs';

import fs from 'fs-promise';
import {
  Observable
}
from '@reactivex/rxjs';
import Promise from 'bluebird';
import {
  gustav
}
from 'gustav';
import {
  basename, extname
}
from 'path';
import json2csv from 'json2csv';
import {
  EOL
}
from 'os';
import {
  logger
}
from './index';
import util from 'util';
import {
  isEmpty, merge
}
from 'lodash';
import {
  printObj
}
from './util';

var toCSV = Promise.promisify(json2csv);

export function createWorkflow(sourceObservable, prompt, file) {
  gustav.source('dibelsSource', () => sourceObservable);
  let config = {
    prompt: prompt,
    file: file
  };
  return gustav.createWorkflow()
    .source('dibelsSource')
    .transf(createTransformer, config)
    .sink(csvObservable, config);
}

function testResultsTransform(config, observable) {
  return observable
    .flatMap(item => {
      const configFile = fs.readFile('./config.json')
        .then(r => JSON.parse(r.toString()))

      const matchingTestScore = getMatchingStudentTestScore(
          item['Student Primary ID'],
          item['School Year'],
          item['Composite Score'],
          config.prompt.testId
        )
        .then(r => {
          // Expecting there to NOT be any matching student test score Record
          if (r.rows.length) {
            const error = {
              studentTestScore: r,
              testResult: item.testResult,
              message: `expected getMatchingStudentTestScore to return 0 records, got ${r.rows.length} rows`
            };

            logger.log('info', `Error checking for matching student test records for student_number: ${item['Student Primary ID']}`, {
              psDbError: printObj(error)
            });

            return new Error(error.message);
          } else {
            return {};
          }
        });

      const studentId = getStudentIdFromStudentNumber(item['Student Primary ID'])

      const allPromises = Promise.all([configFile, matchingTestScore, studentId])
        .then(r => {
          return {
            config: r[0],
            matchingTestScore: r[1],
            studentId: r[2]
          }
        });

      const promisesObs = Observable.fromPromise(allPromises);

      const zipFn = (s1, s2) => {
        console.log('s1 == %j', s1);
        console.log('s2 == %j', s2);
        return {
          testResult: s1,
          config: s2.config,
          matchingTestScore: s2.matchingTestScore,
          studentId: s2.studentId
        };
      }

      let testResultObs = {
        testResult: item
      };

      return Observable.zip(testResultObs, promisesObs, _.merge);

    })
    .filter(item => {
      return isEmpty(item.matchingStudentTestScore) &&
        !isEmpty(item.config) &&
        !!item.studentId;
    })
    .map(item => {
      return {
        'Test Date': item.config.testConstants.ROGL_Begin_Year.testDate,
        'Student Id': item.studentId,
        'Student Number': item.testResult['Student Primary ID'],
        'Grade Level': item.testResult.Grade,
        'Composite Score Alpha': item.testResult['Composite Score']
      }
    });

}

function proficiencyTransform(config, observable) {
  return observable
    .flatMap(item => {
      const matchingTestScore = getMatchingStudentTestScore(
          item['Student Primary ID'],
          item['School Year'],
          item['Composite Score'],
          config.prompt.testId
        )
        .then(r => {
          // Expecting there to NOT be any matching student test score Record
          if (!r.rows.length) {
            throw {
              studentTestScore: r,
              testResult: item,
              message: `expected getMatchingStudentTestScore to return 1 record, got ${r.rows.length} rows`
            };
          } else {
            return r.rows[0].DCID;
          }
        });

      return Observable.zip(
        Observable.fromPromise(matchingTestScore)
        .catch(e => {
          logger.log('info', `Error fetching matching student test score for student_number: ${item['Student Primary ID']}`, {
            psDbError: printObj(e)
          });
          logger.log('info', `dibels record for student_number: ${item['Student Primary ID']}`, {
            sourceData: printObj(item)
          });
        }),

        Observable.of(item),

        (s1, s2) => ({
          matchingTestScore: s1,
          record: s2
        })
      );

    })
    .flatMap(item => {
      let matchingProficiency = getMatchingProficiency(
          item.record['Student Primary ID'],
          item.record['School Year'],
          item.record['Composite Score'],
          config.prompt.testId
        )
        .then(r => {
          if (r.rows.length) {
            throw {
              studentTestScore: r,
              testResult: item.record,
              message: `expected getMatchingProficiency to return 0 records, got ${r.rows.length} rows`
            };
          }
        });

      return Observable.zip(
        Observable.fromPromise(matchingProficiency)
        .catch(e => {
          logger.log('info', `Error fetching matching student proficiency record for student_number: ${item['Student Primary ID']}`, {
            psDbError: printObj(e)
          });
          logger.log('info', `dibels record for student_number: ${item['Student Primary ID']}`, {
            sourceData: printObj(item)
          });
          return Observable.of({});
        }),

        Observable.of(item),

        (s1, s2) => ({
          testResult: s2.record,
          studentTestScore: s2.matchingTestScore,
          proficiency: s1
        })

      )
    })
    .filter(item => {
      // if item.proficiency === {}, no matching proficiency records were found, so allow it through
      // if item.proficiency is not empty, existing proficiency record was found, so do not allow it through
      return isEmpty(item.proficiency);
    })
    .map(item => {
      return {
        studentTestScoreDcid: item.studentTestScore,
        benchmark: item.testResult['Assessment Measure-Composite Score-Levels']
      };
    });
}

/**
 * @return {Observable} Observable that emits data matching the format
 * asked by the user
 */
function createTransformer(config, sourceObservable) {
  if (config.prompt.table === 'Test Results') {
    return testResultsTransform(config, sourceObservable);
  } else if (config.prompt.table === 'U_StudentTestProficiency') {
    return proficiencyTransform(config, sourceObservable);
  }
}

/**
 * maps objects emitted by srcObservable to a new Observable that
 * converts those objects to csv strings and emits the results
 * @param  {Observable}
 * @return {Disposable}
 */
function csvObservable(config, srcObservable) {
  var ws;
  let csvObservable = srcObservable.concatMap(async function(item, i) {
    if (i === 0) {
      /*let outputFilename = `output/${toFileName(item.extra.testProgramDesc)}.txt`;*/
      let outputFilename = `output/${basename(config.file, extname(config.file))}-${config.prompt.table}${extname(config.file)}`;
      console.log('outputFilename == ', outputFilename);
      // creates file if it doesn't exist
      ws = createWriteStream(outputFilename, {
        flags: 'a'
      });

      await fs.truncate(outputFilename);
    }
    return toCSV({
        data: item,
        del: '\t',
        hasCSVColumnTitle: i === 0 // print columns only if this is the first item emitted
      })
      .then(csvStr => {
        let csvRemQuotes = csvStr.replace(/"/g, '');

        // Add a newline character before every line except the first line
        let csv = i === 0 ? csvRemQuotes : EOL + csvRemQuotes;
        return csv;
      });
  });

  return csvObservable.subscribe(item => {
    ws.write(item);
  });
}
<commit_msg>-Fixed _.merge import error -In testResultsTransform, getMatchingStudentTestScore should Return rows object so it can be filtered later, instead of throwing an error. -Observable catch should return an Observable so zip has something to subscri be to<commit_after>require('babel-polyfill');

import {
  getStudentIdFromStudentNumber,
  getMatchingStudentTest,
  getMatchingStudentTestScore,
  getMatchingProficiency
}
from './service';
import {
  createWriteStream
}
from 'fs';

import fs from 'fs-promise';
import {
  Observable
}
from '@reactivex/rxjs';
import Promise from 'bluebird';
import {
  gustav
}
from 'gustav';
import {
  basename, extname
}
from 'path';
import json2csv from 'json2csv';
import {
  EOL
}
from 'os';
import {
  logger
}
from './index';
import util from 'util';
import {
  isEmpty, merge
}
from 'lodash';
import {
  printObj
}
from './util';

var toCSV = Promise.promisify(json2csv);

export function createWorkflow(sourceObservable, prompt, file) {
  gustav.source('dibelsSource', () => sourceObservable);
  let config = {
    prompt: prompt,
    file: file
  };
  return gustav.createWorkflow()
    .source('dibelsSource')
    .transf(createTransformer, config)
    .sink(csvObservable, config);
}

function testResultsTransform(config, observable) {
  return observable
    .flatMap(item => {
      const configFile = fs.readFile('./config.json')
        .then(r => JSON.parse(r.toString()))

      const matchingTestScore = getMatchingStudentTestScore(
          item['Student Primary ID'],
          item['School Year'],
          item['Composite Score'],
          config.prompt.testId
        )
        .then(r => {
          // Expecting there to NOT be any matching student test score Record
          if (r.rows.length) {
            const error = {
              studentTestScore: r,
              testResult: item.testResult,
              message: `expected getMatchingStudentTestScore to return 0 records, got ${r.rows.length} rows`
            };

            logger.log('info', `Error checking for matching student test records for student_number: ${item['Student Primary ID']}`, {
              psDbError: printObj(error)
            });

            return r.rows;
          } else {
            return {};
          }
        });

      const studentId = getStudentIdFromStudentNumber(item['Student Primary ID'])

      const allPromises = Promise.all([configFile, matchingTestScore, studentId])
        .then(r => {
          return {
            config: r[0],
            matchingTestScore: r[1],
            studentId: r[2]
          }
        });

      const promisesObs = Observable.fromPromise(allPromises);

      let testResultObs = Observable.of({
        testResult: item
      });

      return Observable.zip(testResultObs, promisesObs, merge);

    })
    .filter(item => {

      // return true (allow through filter) if the following criteria are met:
      // 1) no matching student test score record was found
      // 2) the config file object is not empty
      // 3) studentId is not falsey (not found)
      return !item.matchingTestScore.length &&
        !isEmpty(item.config) &&
        !!item.studentId;
    })
    .map(item => {
      return {
        'Test Date': item.config.testConstants.ROGL_Begin_Year.testDate,
        'Student Id': item.studentId,
        'Student Number': item.testResult['Student Primary ID'],
        'Grade Level': item.testResult.Grade,
        'Composite Score Alpha': item.testResult['Composite Score']
      }
    });

}

function proficiencyTransform(config, observable) {
  return observable
    .flatMap(item => {
      const matchingTestScore = getMatchingStudentTestScore(
          item['Student Primary ID'],
          item['School Year'],
          item['Composite Score'],
          config.prompt.testId
        )
        .then(r => {
          // Expecting there to be 1 matching student test score record
          if (!r.rows.length) {
            throw {
              studentTestScore: r,
              testResult: item,
              message: `expected getMatchingStudentTestScore to return 1 record, got ${r.rows.length} rows`
            };
          } else {
            return r.rows[0].DCID;
          }
        });

      return Observable.zip(
        Observable.fromPromise(matchingTestScore)
        .catch(e => {
          logger.log('info', `Error fetching matching student test score for student_number: ${item['Student Primary ID']}`, {
            psDbError: printObj(e)
          });
          logger.log('info', `dibels record for student_number: ${item['Student Primary ID']}`, {
            sourceData: printObj(item)
          });
          return Observable.of({});
        }),

        Observable.of(item),

        (s1, s2) => ({
          matchingTestScore: s1,
          record: s2
        })
      );

    })
    .flatMap(item => {
      let matchingProficiency = getMatchingProficiency(
          item.record['Student Primary ID'],
          item.record['School Year'],
          item.record['Composite Score'],
          config.prompt.testId
        )
        .then(r => {
          if (r.rows.length) {
            throw {
              studentTestScore: r,
              testResult: item.record,
              message: `expected getMatchingProficiency to return 0 records, got ${r.rows.length} rows`
            };
          }
        });

      return Observable.zip(
        Observable.fromPromise(matchingProficiency)
        .catch(e => {
          logger.log('info', `Error fetching matching student proficiency record for student_number: ${item['Student Primary ID']}`, {
            psDbError: printObj(e)
          });
          logger.log('info', `dibels record for student_number: ${item['Student Primary ID']}`, {
            sourceData: printObj(item)
          });
          return Observable.of({});
        }),

        Observable.of(item),

        (s1, s2) => ({
          testResult: s2.record,
          studentTestScore: s2.matchingTestScore,
          proficiency: s1
        })
      )
    })
    .filter(item => {
      // if item.proficiency === {}, no matching proficiency records were found, so allow it through
      // if item.proficiency is not empty, existing proficiency record was found, so do not allow it through
      return isEmpty(item.proficiency);
    })
    .map(item => {
      return {
        studentTestScoreDcid: item.studentTestScore,
        benchmark: item.testResult['Assessment Measure-Composite Score-Levels']
      };
    });
}

/**
 * @return {Observable} Observable that emits data matching the format
 * asked by the user
 */
function createTransformer(config, sourceObservable) {
  if (config.prompt.table === 'Test Results') {
    return testResultsTransform(config, sourceObservable);
  } else if (config.prompt.table === 'U_StudentTestProficiency') {
    return proficiencyTransform(config, sourceObservable);
  }
}

/**
 * maps objects emitted by srcObservable to a new Observable that
 * converts those objects to csv strings and emits the results
 * @param  {Observable}
 * @return {Disposable}
 */
function csvObservable(config, srcObservable) {
  var ws;
  let csvObservable = srcObservable.concatMap(async function(item, i) {
    if (i === 0) {
      /*let outputFilename = `output/${toFileName(item.extra.testProgramDesc)}.txt`;*/
      let outputFilename = `output/${basename(config.file, extname(config.file))}-${config.prompt.table}${extname(config.file)}`;
      console.log('outputFilename == ', outputFilename);
      // creates file if it doesn't exist
      ws = createWriteStream(outputFilename, {
        flags: 'a'
      });

      await fs.truncate(outputFilename);
    }
    return toCSV({
        data: item,
        del: '\t',
        hasCSVColumnTitle: i === 0 // print columns only if this is the first item emitted
      })
      .then(csvStr => {
        let csvRemQuotes = csvStr.replace(/"/g, '');

        // Add a newline character before every line except the first line
        let csv = i === 0 ? csvRemQuotes : EOL + csvRemQuotes;
        return csv;
      });
  });

  return csvObservable.subscribe(item => {
    ws.write(item);
  });
}
<|endoftext|>


<commit_before>/*
 * Simple jQuery Dialog
 * https://github.com/filamentgroup/dialog
 *
 * Copyright (c) 2013 Filament Group, Inc.
 * Author: @scottjehl
 * Contributors: @johnbender, @zachleat
 * Licensed under the MIT, GPL licenses.
 */

window.jQuery = window.jQuery || window.shoestring;

(function( w, $ ){
	w.componentNamespace = w.componentNamespace || w;

	var pluginName = "dialog", cl, ev,
		doc = w.document,
		docElem = doc.documentElement,
		body = doc.body,
		$html = $( docElem );

	var Dialog = w.componentNamespace.Dialog = function( element ){
		this.$el = $( element );

		// prevent double init
		if( this.$el.data( pluginName ) ){
			return this.$el.data( pluginName );
		}

		// record init
		this.$el.data( pluginName, this );

		// keeping data-nobg here for compat. Deprecated.
		this.$background = !this.$el.is( '[data-' + pluginName + '-nobg]' ) ?
			$( doc.createElement('div') ).addClass( cl.bkgd ).attr( "tabindex", "-1" ).appendTo( "body") :
			$( [] );

		// when dialog first inits, save a reference to the initial hash so we can know whether
		// there's room in the history stack to go back or not when closing
		this.initialLocationHash = w.location.hash;

		// the dialog's url hash is different from the dialog's actual ID attribute
		// this is because pairing the ID directly makes the browser jump to the top
		// of the dialog, rather than allowing us to space it off the top of the
		// viewport. also, if the dialog has a data-history attr, this property will
		// prevent its findability for onload and hashchanges
		this.nohistory =
			this.$el.attr( 'data-dialog-history' ) === "false" || !Dialog.history;

		// use the identifier and an extra tag for hash management
		this.hash = this.$el.attr( "id" ) + "-dialog";

		// if won't pop up the dialog on initial load (`nohistory`) the user MAY
		// refresh a url with the dialog id as the hash then a change of the hash
		// won't be recognized by the browser when the dialog comes up and the back
		// button will return to the referring page. So, when nohistory is defined,
		// we append a "unique" identifier to the hash.
		this.hash += this.nohistory ? "-" + Date.now().toString() : "" ;

		this.isOpen = false;
		this.isTransparentBackground = this.$el.is( '[data-transbg]' );

		this._addA11yAttrs();
	};

  // default to tracking history with the dialog
  Dialog.history = true;

	Dialog.events = ev = {
		open: pluginName + "-open",
		opened: pluginName + "-opened",
		close: pluginName + "-close",
		closed: pluginName + "-closed"
	};

	Dialog.classes = cl = {
		open: pluginName + "-open",
		opened: pluginName + "-opened",
		content: pluginName + "-content",
		close: pluginName + "-close",
		closed: pluginName + "-closed",
		bkgd: pluginName + "-background",
		bkgdOpen: pluginName + "-background-open",
		bkgdTrans: pluginName + "-background-trans"
	};

	Dialog.selectors = {
		close: "." + Dialog.classes.close + ", [data-close], [data-dialog-close]"
	};

	Dialog.prototype.destroy = function() {
		// unregister the focus stealing
		window.focusRegistry.unregister(this);

		// clear init for this dom element
		this.$el.data()[pluginName] = undefined;

		// remove the backdrop for the dialog
		this.$background.remove();
	};

	Dialog.prototype.checkFocus = function(event){
		var $target = $( event.target );
		var shouldSteal;

		shouldSteal =
			this.isOpen &&
			!$target.closest( this.$el[0]).length &&
			this.isLastDialog() &&
			!this._isNonInteractive();

		return shouldSteal;
	};

	Dialog.prototype.stealFocus = function(){
		this.$el[0].focus();
	};

	Dialog.prototype._addA11yAttrs = function(){
		this.$el.attr( "role", "dialog" );
		this.$el.attr( "tabindex", "0" );
	};

	Dialog.prototype._removeA11yAttrs = function(){
		this.$el.removeAttr( "role" );
		this.$el.removeAttr( "tabindex" );
	};

	Dialog.prototype._isNonInteractive = function(){
		var computedDialog = window.getComputedStyle( this.$el[ 0 ], null );
		var closeLink = this.$el.find( Dialog.selectors.close )[0];
		var computedCloseLink;
		if( closeLink ){
			computedCloseLink = window.getComputedStyle( closeLink, null );
		}
		var computedBackground = window.getComputedStyle( this.$background[ 0 ], null );
		return computedDialog.getPropertyValue( "display" ) !== "none" &&
			computedDialog.getPropertyValue( "visibility" ) !== "hidden" &&
			( !computedCloseLink || computedCloseLink.getPropertyValue( "display" ) === "none" ) &&
			computedBackground.getPropertyValue( "display" ) === "none";
	};

	Dialog.prototype._checkInteractivity = function(){
		if( this._isNonInteractive() ){
			this._removeA11yAttrs();
			this._ariaShowUnrelatedElems();
		}
		else{
			this._addA11yAttrs();

		}
	};

	Dialog.prototype._ariaHideUnrelatedElems = function(){
		this._ariaShowUnrelatedElems();
		var ignoredElems = "script, style";
		var hideList = this.$el.siblings().not( ignoredElems );
		this.$el.parents().not( "body, html" ).each(function(){
			hideList = hideList.add( $( this ).siblings().not( ignoredElems ) );
		});
		hideList.each(function(){
			var priorHidden = $( this ).attr( "aria-hidden" ) || "";
			$( this )
				.attr( "data-dialog-aria-hidden", priorHidden )
				.attr( "aria-hidden", "true" );
		});
	};

	Dialog.prototype._ariaShowUnrelatedElems = function(){
		$( "[data-dialog-aria-hidden]" ).each(function(){
			if( $( this ).attr( "data-dialog-aria-hidden" ).match( "true|false" ) ){
				$( this ).attr( "aria-hidden", $( this ).attr( "data-dialog-aria-hidden" ) );
			}
			else {
				$( this ).removeAttr( "aria-hidden" );
			}
		}).removeAttr( "data-dialog-aria-hidden" );
	};

	Dialog.prototype.open = function() {
		if( this.isOpen ){
			return;
		}

		if( this.$background.length ) {
			this.$background[ 0 ].style.height = Math.max( docElem.scrollHeight, docElem.clientHeight ) + "px";
		}
		this.$el.addClass( cl.open );
		this.$background.addClass( cl.bkgdOpen );
		this.$background.attr( "id", this.$el.attr( "id" ) + "-background" );
		this._setBackgroundTransparency();

		this.scroll = "pageYOffset" in w ? w.pageYOffset : ( docElem.scrollY || docElem.scrollTop || ( body && body.scrollY ) || 0 );
		this.$el[ 0 ].style.top = this.scroll + "px";

		$html.addClass( cl.open );
		this.isOpen = true;

		var cleanHash = w.location.hash.replace( /^#/, "" );

		if( cleanHash.indexOf( "-dialog" ) > -1 && !this.isLastDialog() ){
			w.location.hash += "#" + this.hash;
		} else if( !this.isLastDialog() ){
			w.location.hash = this.hash;
		}

		if( doc.activeElement ){
			this.focused = doc.activeElement;
		}

		this.$el[ 0 ].focus();
		var self = this;
		setTimeout(function(){
			self._ariaHideUnrelatedElems();
		});

		this.$el.trigger( ev.opened );
	};

	Dialog.prototype.lastHash = function(){
		return w.location.hash.split( "#" ).pop();
	};

	// is this the newest/last dialog that was opened based on the hash
	Dialog.prototype.isLastDialog = function(){
		return this.lastHash() === this.hash;
	};

	Dialog.prototype._setBackgroundTransparency = function() {
		if( this.isTransparentBackground ){
			this.$background.addClass( cl.bkgdTrans );
		}
	};

	Dialog.prototype.close = function(){
		if( !this.isOpen ){
			return;
		}

		this._ariaShowUnrelatedElems();

		// if close() is called directly and the hash for this dialog is at the end
		// of the url, then we need to change the hash to remove it, either by going
		// back if we can, or by adding a history state that doesn't have it at the
		// end
		if( window.location.hash.split( "#" ).pop() === this.hash ){
			// let's check if the first segment in the hash is the same as the first
			// segment in the initial hash if not, it's safe to use back() to close
			// this out and clean the hash up
			var firstHashSegment = window.location.hash.split( "#" )[ 1 ];
			var firstInitialHashSegment = this.initialLocationHash.split( "#" )[ 1 ];
			if( firstHashSegment && firstInitialHashSegment && firstInitialHashSegment !== firstHashSegment ){
				window.history.back();
			}
			// otherwise, if it's the same starting hash as it was at init time, we
			// can't trigger back to close the dialog, as it might take us elsewhere.
			// so we have to go forward and create a new hash that does not have this
			// dialog's hash at the end
			else {
				var escapedRegexpHash = this
            .hash
            .replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");

				window.location.hash = window
          .location
          .hash
          .replace( new RegExp( "#" + escapedRegexpHash + "$" ), "" );
			}
			return;
		}

		this.$el.removeClass( cl.open );

		this.$background.removeClass( cl.bkgdOpen );

		this.isOpen = false;

		// we only want to throw focus on close if we aren't
		// opening a nested dialog or some other UI state
		if( this.focused && !this.isLastDialog()){
				this.focused.focus();
		}
		if( $( "." + pluginName + "." + cl.open ).length === 0 ){
			$html.removeClass( cl.open );
			w.scrollTo( 0, this.scroll );
		}

		this.$el.trigger( ev.closed );
	};
}( this, window.jQuery ));
<commit_msg>use -1 tabindex so it can gain programatic focus but not key<commit_after>/*
 * Simple jQuery Dialog
 * https://github.com/filamentgroup/dialog
 *
 * Copyright (c) 2013 Filament Group, Inc.
 * Author: @scottjehl
 * Contributors: @johnbender, @zachleat
 * Licensed under the MIT, GPL licenses.
 */

window.jQuery = window.jQuery || window.shoestring;

(function( w, $ ){
	w.componentNamespace = w.componentNamespace || w;

	var pluginName = "dialog", cl, ev,
		doc = w.document,
		docElem = doc.documentElement,
		body = doc.body,
		$html = $( docElem );

	var Dialog = w.componentNamespace.Dialog = function( element ){
		this.$el = $( element );

		// prevent double init
		if( this.$el.data( pluginName ) ){
			return this.$el.data( pluginName );
		}

		// record init
		this.$el.data( pluginName, this );

		// keeping data-nobg here for compat. Deprecated.
		this.$background = !this.$el.is( '[data-' + pluginName + '-nobg]' ) ?
			$( doc.createElement('div') ).addClass( cl.bkgd ).attr( "tabindex", "-1" ).appendTo( "body") :
			$( [] );

		// when dialog first inits, save a reference to the initial hash so we can know whether
		// there's room in the history stack to go back or not when closing
		this.initialLocationHash = w.location.hash;

		// the dialog's url hash is different from the dialog's actual ID attribute
		// this is because pairing the ID directly makes the browser jump to the top
		// of the dialog, rather than allowing us to space it off the top of the
		// viewport. also, if the dialog has a data-history attr, this property will
		// prevent its findability for onload and hashchanges
		this.nohistory =
			this.$el.attr( 'data-dialog-history' ) === "false" || !Dialog.history;

		// use the identifier and an extra tag for hash management
		this.hash = this.$el.attr( "id" ) + "-dialog";

		// if won't pop up the dialog on initial load (`nohistory`) the user MAY
		// refresh a url with the dialog id as the hash then a change of the hash
		// won't be recognized by the browser when the dialog comes up and the back
		// button will return to the referring page. So, when nohistory is defined,
		// we append a "unique" identifier to the hash.
		this.hash += this.nohistory ? "-" + Date.now().toString() : "" ;

		this.isOpen = false;
		this.isTransparentBackground = this.$el.is( '[data-transbg]' );

		this._addA11yAttrs();
	};

  // default to tracking history with the dialog
  Dialog.history = true;

	Dialog.events = ev = {
		open: pluginName + "-open",
		opened: pluginName + "-opened",
		close: pluginName + "-close",
		closed: pluginName + "-closed"
	};

	Dialog.classes = cl = {
		open: pluginName + "-open",
		opened: pluginName + "-opened",
		content: pluginName + "-content",
		close: pluginName + "-close",
		closed: pluginName + "-closed",
		bkgd: pluginName + "-background",
		bkgdOpen: pluginName + "-background-open",
		bkgdTrans: pluginName + "-background-trans"
	};

	Dialog.selectors = {
		close: "." + Dialog.classes.close + ", [data-close], [data-dialog-close]"
	};

	Dialog.prototype.destroy = function() {
		// unregister the focus stealing
		window.focusRegistry.unregister(this);

		// clear init for this dom element
		this.$el.data()[pluginName] = undefined;

		// remove the backdrop for the dialog
		this.$background.remove();
	};

	Dialog.prototype.checkFocus = function(event){
		var $target = $( event.target );
		var shouldSteal;

		shouldSteal =
			this.isOpen &&
			!$target.closest( this.$el[0]).length &&
			this.isLastDialog() &&
			!this._isNonInteractive();

		return shouldSteal;
	};

	Dialog.prototype.stealFocus = function(){
		this.$el[0].focus();
	};

	Dialog.prototype._addA11yAttrs = function(){
		this.$el.attr( "role", "dialog" );
		this.$el.attr( "tabindex", "-1" );
	};

	Dialog.prototype._removeA11yAttrs = function(){
		this.$el.removeAttr( "role" );
		this.$el.removeAttr( "tabindex" );
	};

	Dialog.prototype._isNonInteractive = function(){
		var computedDialog = window.getComputedStyle( this.$el[ 0 ], null );
		var closeLink = this.$el.find( Dialog.selectors.close )[0];
		var computedCloseLink;
		if( closeLink ){
			computedCloseLink = window.getComputedStyle( closeLink, null );
		}
		var computedBackground = window.getComputedStyle( this.$background[ 0 ], null );
		return computedDialog.getPropertyValue( "display" ) !== "none" &&
			computedDialog.getPropertyValue( "visibility" ) !== "hidden" &&
			( !computedCloseLink || computedCloseLink.getPropertyValue( "display" ) === "none" ) &&
			computedBackground.getPropertyValue( "display" ) === "none";
	};

	Dialog.prototype._checkInteractivity = function(){
		if( this._isNonInteractive() ){
			this._removeA11yAttrs();
			this._ariaShowUnrelatedElems();
		}
		else{
			this._addA11yAttrs();

		}
	};

	Dialog.prototype._ariaHideUnrelatedElems = function(){
		this._ariaShowUnrelatedElems();
		var ignoredElems = "script, style";
		var hideList = this.$el.siblings().not( ignoredElems );
		this.$el.parents().not( "body, html" ).each(function(){
			hideList = hideList.add( $( this ).siblings().not( ignoredElems ) );
		});
		hideList.each(function(){
			var priorHidden = $( this ).attr( "aria-hidden" ) || "";
			$( this )
				.attr( "data-dialog-aria-hidden", priorHidden )
				.attr( "aria-hidden", "true" );
		});
	};

	Dialog.prototype._ariaShowUnrelatedElems = function(){
		$( "[data-dialog-aria-hidden]" ).each(function(){
			if( $( this ).attr( "data-dialog-aria-hidden" ).match( "true|false" ) ){
				$( this ).attr( "aria-hidden", $( this ).attr( "data-dialog-aria-hidden" ) );
			}
			else {
				$( this ).removeAttr( "aria-hidden" );
			}
		}).removeAttr( "data-dialog-aria-hidden" );
	};

	Dialog.prototype.open = function() {
		if( this.isOpen ){
			return;
		}

		if( this.$background.length ) {
			this.$background[ 0 ].style.height = Math.max( docElem.scrollHeight, docElem.clientHeight ) + "px";
		}
		this.$el.addClass( cl.open );
		this.$background.addClass( cl.bkgdOpen );
		this.$background.attr( "id", this.$el.attr( "id" ) + "-background" );
		this._setBackgroundTransparency();

		this.scroll = "pageYOffset" in w ? w.pageYOffset : ( docElem.scrollY || docElem.scrollTop || ( body && body.scrollY ) || 0 );
		this.$el[ 0 ].style.top = this.scroll + "px";

		$html.addClass( cl.open );
		this.isOpen = true;

		var cleanHash = w.location.hash.replace( /^#/, "" );

		if( cleanHash.indexOf( "-dialog" ) > -1 && !this.isLastDialog() ){
			w.location.hash += "#" + this.hash;
		} else if( !this.isLastDialog() ){
			w.location.hash = this.hash;
		}

		if( doc.activeElement ){
			this.focused = doc.activeElement;
		}

		this.$el[ 0 ].focus();
		var self = this;
		setTimeout(function(){
			self._ariaHideUnrelatedElems();
		});

		this.$el.trigger( ev.opened );
	};

	Dialog.prototype.lastHash = function(){
		return w.location.hash.split( "#" ).pop();
	};

	// is this the newest/last dialog that was opened based on the hash
	Dialog.prototype.isLastDialog = function(){
		return this.lastHash() === this.hash;
	};

	Dialog.prototype._setBackgroundTransparency = function() {
		if( this.isTransparentBackground ){
			this.$background.addClass( cl.bkgdTrans );
		}
	};

	Dialog.prototype.close = function(){
		if( !this.isOpen ){
			return;
		}

		this._ariaShowUnrelatedElems();

		// if close() is called directly and the hash for this dialog is at the end
		// of the url, then we need to change the hash to remove it, either by going
		// back if we can, or by adding a history state that doesn't have it at the
		// end
		if( window.location.hash.split( "#" ).pop() === this.hash ){
			// let's check if the first segment in the hash is the same as the first
			// segment in the initial hash if not, it's safe to use back() to close
			// this out and clean the hash up
			var firstHashSegment = window.location.hash.split( "#" )[ 1 ];
			var firstInitialHashSegment = this.initialLocationHash.split( "#" )[ 1 ];
			if( firstHashSegment && firstInitialHashSegment && firstInitialHashSegment !== firstHashSegment ){
				window.history.back();
			}
			// otherwise, if it's the same starting hash as it was at init time, we
			// can't trigger back to close the dialog, as it might take us elsewhere.
			// so we have to go forward and create a new hash that does not have this
			// dialog's hash at the end
			else {
				var escapedRegexpHash = this
            .hash
            .replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");

				window.location.hash = window
          .location
          .hash
          .replace( new RegExp( "#" + escapedRegexpHash + "$" ), "" );
			}
			return;
		}

		this.$el.removeClass( cl.open );

		this.$background.removeClass( cl.bkgdOpen );

		this.isOpen = false;

		// we only want to throw focus on close if we aren't
		// opening a nested dialog or some other UI state
		if( this.focused && !this.isLastDialog()){
				this.focused.focus();
		}
		if( $( "." + pluginName + "." + cl.open ).length === 0 ){
			$html.removeClass( cl.open );
			w.scrollTo( 0, this.scroll );
		}

		this.$el.trigger( ev.closed );
	};
}( this, window.jQuery ));
<|endoftext|>


<commit_before>require('babel-polyfill');

import { createWriteStream } from 'fs';
import fs from 'fs-promise';
import { Observable } from '@reactivex/rxjs';
import Promise from 'bluebird';
import { gustav } from 'gustav';
import { basename, extname } from 'path';
import json2csv from 'json2csv';
import { EOL } from 'os';
import util from 'util';
import { isEmpty, merge } from 'lodash';

import {
  studentTestScoreDuplicateCheck,
  proficiencyDuplicateCheck,
  studentNumberToStudentId,
  testRecordToMatchingDcid
}
from './blogic';
import { printObj } from './util';
import { logger, config } from './index';

var toCSV = Promise.promisify(json2csv);

export function createWorkflow(sourceObservable, prompt, inputFile) {
  gustav.source('dibelsSource', () => sourceObservable);

  let config = {
    prompt: prompt,
    inputFile: inputFile
  };
  return gustav.createWorkflow()
    .source('dibelsSource')
    .transf(createTransformer, config)
    .sink(csvObservable, config);
}

function testResultsTransform(config, observable) {
  return observable
    .flatMap(item => {
      const matchingTestScore = studentTestScoreDuplicateCheck(
        item['Student Primary ID'],
        item['School Year'],
        item['Composite Score'],
        config.prompt.testId,
        item);

      return Observable.zip(
        studentNumberToStudentId(item['Student Primary ID'], item).do(x => console.log('x == ', x)),
        matchingTestScore,

        (studentId, matchingTest) => {
          console.log('studentId == ', studentId);
          console.log('matchingTest == ', matchingTest);
          return {
            studentId: studentId,
            matchingTestScore: matchingTest
          };
        }
      );
    })
    .map(item => {
      console.log('item == ', item);
      return {
        'Test Date': item.config.testConstants.ROGL_Begin_Year.testDate,
        'Student Id': item.studentId,
        'Student Number': item.testResult['Student Primary ID'],
        'Grade Level': item.testResult.Grade,
        'Composite Score Alpha': item.testResult['Composite Score']
      };
    });
}

function proficiencyTransform(config, observable) {
  return observable
    .flatMap(item => {
      const matchingTestScore = testRecordToMatchingDcid(
        item['Student Primary ID'],
        item['School Year'],
        item['Composite Score'],
        config.prompt.testId,
        item);

      return Observable.zip(
        matchingTestScore,
        Observable.of(item),

        (s1, s2) => ({
          matchingTestScore: s1,
          record: s2
        })
      );
    })
    .flatMap(item => {
      let matchingProficiency = proficiencyDuplicateCheck(
        item.record['Student Primary ID'],
        item.record['School Year'],
        item.record['Composite Score'],
        config.prompt.testId,
        item
      );

      return Observable.zip(
        matchingProficiency,

        Observable.of(item),

        (_, testRecord) => ({
          testResult: testRecord.record,
          studentTestScore: testRecord.matchingTestScore
        })
      )
    })
    .map(item => {
      return {
        studentTestScoreDcid: item.studentTestScore,
        benchmark: item.testResult['Assessment Measure-Composite Score-Levels']
      };
    });
}

/**
 * @return {Observable} Observable that emits data matching the format
 * asked by the user
 */
function createTransformer(config, sourceObservable) {
  if (config.prompt.table === 'Test Results') {
    return testResultsTransform(config, sourceObservable);
  } else if (config.prompt.table === 'U_StudentTestProficiency') {
    return proficiencyTransform(config, sourceObservable);
  }
}

/**
 * maps objects emitted by srcObservable to a new Observable that
 * converts those objects to csv strings and emits the results
 *
 * @param  {object}     config
 * @param  {Observable} srcObservable
 * @return {Disposable}
 */
function csvObservable(config, srcObservable) {
  var ws;
  let csvObservable = srcObservable.concatMap(async function (item, i) {
    if (i === 0) {
      let outputFilename = `output/rogl/${basename(config.inputFile, extname(config.inputFile)) }-${config.prompt.table}${extname(config.inputFile) }`;
      console.log(outputFilename);

      // creates file if it doesn't exist
      ws = createWriteStream(outputFilename, {
        flags: 'a'
      });

      await fs.truncate(outputFilename);
    }
    return toCSV({
        data: item,
        del: '\t',
        hasCSVColumnTitle: i === 0 // print columns only if this is the first item emitted
      })
      .then(csvStr => {
        let csvRemQuotes = csvStr.replace(/"/g, '');

        // Add a newline character before every line except the first line
        let csv = i === 0 ? csvRemQuotes : EOL + csvRemQuotes;
        console.log('csv == ' + csv);
        return csv;
      });
  });

  return csvObservable.subscribe(item => ws.write(item));
}
<commit_msg>Added score name to testScoreDuplicateCheck call<commit_after>require('babel-polyfill');

import { createWriteStream } from 'fs';
import fs from 'fs-promise';
import { Observable } from '@reactivex/rxjs';
import Promise from 'bluebird';
import { gustav } from 'gustav';
import { basename, extname } from 'path';
import json2csv from 'json2csv';
import { EOL } from 'os';
import util from 'util';
import { isEmpty, merge } from 'lodash';

import {
  studentTestScoreDuplicateCheck,
  proficiencyDuplicateCheck,
  studentNumberToStudentId,
  testRecordToMatchingDcid
}
from './blogic';
import { printObj } from './util';
import { logger, config } from './index';

var toCSV = Promise.promisify(json2csv);

export function createWorkflow(sourceObservable, prompt, inputFile) {
  gustav.source('dibelsSource', () => sourceObservable);

  let config = {
    prompt: prompt,
    inputFile: inputFile
  };
  return gustav.createWorkflow()
    .source('dibelsSource')
    .transf(createTransformer, config)
    .sink(csvObservable, config);
}

function testResultsTransform(config, observable) {
  return observable
    .flatMap(item => {
      const matchingTestScore = studentTestScoreDuplicateCheck(
        item['Student Primary ID'],
        item['School Year'],
        item['Composite Score'],
        config.prompt.testId,
        'Composite',
        item);

      return Observable.zip(
        studentNumberToStudentId(item['Student Primary ID'], item).do(x => console.log('x == ', x)),
        matchingTestScore,

        (studentId, matchingTest) => {
          console.log('studentId == ', studentId);
          console.log('matchingTest == ', matchingTest);
          return {
            studentId: studentId,
            matchingTestScore: matchingTest
          };
        }
      );
    })
    .map(item => {
      console.log('item == ', item);
      return {
        'Test Date': item.config.testConstants.ROGL_Begin_Year.testDate,
        'Student Id': item.studentId,
        'Student Number': item.testResult['Student Primary ID'],
        'Grade Level': item.testResult.Grade,
        'Composite Score Alpha': item.testResult['Composite Score']
      };
    });
}

function proficiencyTransform(config, observable) {
  return observable
    .flatMap(item => {
      const matchingTestScore = testRecordToMatchingDcid(
        item['Student Primary ID'],
        item['School Year'],
        item['Composite Score'],
        config.prompt.testId,
        item);

      return Observable.zip(
        matchingTestScore,
        Observable.of(item),

        (s1, s2) => ({
          matchingTestScore: s1,
          record: s2
        })
      );
    })
    .flatMap(item => {
      let matchingProficiency = proficiencyDuplicateCheck(
        item.record['Student Primary ID'],
        item.record['School Year'],
        item.record['Composite Score'],
        config.prompt.testId,
        item
      );

      return Observable.zip(
        matchingProficiency,

        Observable.of(item),

        (_, testRecord) => ({
          testResult: testRecord.record,
          studentTestScore: testRecord.matchingTestScore
        })
      )
    })
    .map(item => {
      return {
        studentTestScoreDcid: item.studentTestScore,
        benchmark: item.testResult['Assessment Measure-Composite Score-Levels']
      };
    });
}

/**
 * @return {Observable} Observable that emits data matching the format
 * asked by the user
 */
function createTransformer(config, sourceObservable) {
  if (config.prompt.table === 'Test Results') {
    return testResultsTransform(config, sourceObservable);
  } else if (config.prompt.table === 'U_StudentTestProficiency') {
    return proficiencyTransform(config, sourceObservable);
  }
}

/**
 * maps objects emitted by srcObservable to a new Observable that
 * converts those objects to csv strings and emits the results
 *
 * @param  {object}     config
 * @param  {Observable} srcObservable
 * @return {Disposable}
 */
function csvObservable(config, srcObservable) {
  var ws;
  let csvObservable = srcObservable.concatMap(async function (item, i) {
    if (i === 0) {
      let outputFilename = `output/rogl/${basename(config.inputFile, extname(config.inputFile)) }-${config.prompt.table}${extname(config.inputFile) }`;
      console.log(outputFilename);

      // creates file if it doesn't exist
      ws = createWriteStream(outputFilename, {
        flags: 'a'
      });

      await fs.truncate(outputFilename);
    }
    return toCSV({
        data: item,
        del: '\t',
        hasCSVColumnTitle: i === 0 // print columns only if this is the first item emitted
      })
      .then(csvStr => {
        let csvRemQuotes = csvStr.replace(/"/g, '');

        // Add a newline character before every line except the first line
        let csv = i === 0 ? csvRemQuotes : EOL + csvRemQuotes;
        console.log('csv == ' + csv);
        return csv;
      });
  });

  return csvObservable.subscribe(item => ws.write(item));
}
<|endoftext|>


<commit_before>/*
Copyright 2016 First People's Cultural Council

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { Component, PropTypes } from 'react'
// import ReactDOM from 'react-dom'

// REDUX
import { connect } from 'react-redux'
import { changeTheme } from 'providers/redux/reducers/navigation'
import { nuxeoConnect, getCurrentUser } from 'providers/redux/reducers/nuxeo'
import { fetchDialect2 } from 'providers/redux/reducers/fvDialect'

import selectn from 'selectn'

import ProviderHelpers from 'common/ProviderHelpers'
// import StringHelpers from 'common/StringHelpers'
import UIHelpers from 'common/UIHelpers'

// import AuthorizationFilter from 'views/components/Document/AuthorizationFilter'

import AppFrontController from './AppFrontController'

import Shepherd from 'tether-shepherd'

// import FontIcon from 'material-ui/lib/font-icon'
// import Paper from 'material-ui/lib/paper'
// import FlatButton from 'material-ui/lib/flat-button'

import IntlService from 'views/services/intl'

// const getPosition = function getPosition() {
//   const doc = document
//   const w = window
//   let x
//   let y
//   let docEl

//   if (typeof w.pageYOffset === 'number') {
//     x = w.pageXOffset
//     y = w.pageYOffset
//   } else {
//     docEl = doc.compatMode && doc.compatMode === 'CSS1Compat' ? doc.documentElement : doc.body
//     x = docEl.scrollLeft
//     y = docEl.scrollTop
//   }
//   return { x: x, y: y }
// }

/**
 * Finds the xPath for a component, leading up to the 'app-wrapper'.
 * Used as a utility for creating Shepherd tours
 */
function findComponentParents(_el) {
  let parents = []
  let el = _el
  const originalEl = el

  if (!el.getAttribute('data-component-id')) {
    return null
  }

  while (el.parentNode) {
    el = el.parentNode

    if (el.getAttribute('id') === 'app-wrapper') {
      break
    }

    if (el.tagName) {
      const appendClass = el.className ? '.' + el.className.replace(/\s/g, '.').replace(/\:/g, '\\:') : '' // eslint-disable-line
      const appendData = el.getAttribute('data-component-id')
        ? "[data-component-id='" + el.getAttribute('data-component-id') + "']"
        : ''

      parents.push(el.tagName.toLowerCase() + appendClass + appendData)
    }
  }

  parents = parents.reverse()
  parents.push(
    originalEl.tagName.toLowerCase() + "[data-component-id='" + originalEl.getAttribute('data-component-id') + "']"
  )

  return parents.join(' ')
}

const getPreferences = function getPreferences(login, dialect) {
  const preferenceString = selectn('response.properties.preferences', login)
  const parsedPreferences = preferenceString ? JSON.parse(preferenceString) : {}
  const flattenedPreferences = {}

  for (const preferenceCat in parsedPreferences) {
    for (const preference in parsedPreferences[preferenceCat]) {
      flattenedPreferences[preference] = parsedPreferences[preferenceCat][preference]
    }
  }

  // Dialect assignment
  flattenedPreferences.primary_dialect_path = selectn('path', dialect)

  return flattenedPreferences
}

const { array, func, object, string } = PropTypes

class AppWrapper extends Component {
  intl = IntlService.instance
  intlBaseKey = 'views'

  static propTypes = {
    // REDUX: actions/dispatch/func
    changeTheme: func.isRequired,
    fetchDialect2: func.isRequired,
    getCurrentUser: func.isRequired,
    nuxeoConnect: func.isRequired,
    // REDUX: reducers/state
    computeDialect2: object.isRequired,
    computeLogin: object.isRequired,
    properties: object.isRequired,
    splitWindowPath: array.isRequired,
    windowPath: string.isRequired,
  }

  static childContextTypes = {
    muiTheme: React.PropTypes.object,
  }

  // react-redux-provide will pass context such as providers (Note: this is only needed for debugging the store atm)
  static contextTypes = {
    providers: PropTypes.object,
  }

  // TODO: The legacy context API will be removed in a future major version.
  // TODO: Use the new context API introduced with version 16.3.
  // TODO: The legacy API will continue working for all 16.x releases.
  // via: https://reactjs.org/docs/legacy-context.html

  /**
   * Pass essential context to all children
   */
  getChildContext() {
    const newContext = {
      muiTheme: this.props.properties.theme.palette,
    }

    return newContext
  }

  constructor(props, context) {
    super(props, context)

    // Connect to Nuxeo
    this.props.nuxeoConnect()
    this.props.getCurrentUser()

    this.state = {
      adminGuideStarted: false,
      dialect: null,
    }

    // Bind methods to 'this'
    ;['_startAdminGuideAssist'].forEach((method) => (this[method] = this[method].bind(this)))
  }

  // Force update of theme if out of sync
  // This is a fix that may be unecessary in future versions of Material-UI, React, Reat-redux-provide
  componentWillReceiveProps(nextProps) {
    if (nextProps.properties.theme.id != this.props.properties.theme.id) {
      nextProps.changeTheme(nextProps.properties.theme.id)
    }
  }

  // Changing a theme manually...
  /*_changeTheme(event) {
      let index = event.nativeEvent.target.selectedIndex;
      this.props.changeTheme(event.target[index].value);
    }*/

  _startAdminGuideAssist() {
    const doms = document.querySelectorAll('[data-component-id]')

    const tour = new Shepherd.Tour({
      defaults: {
        classes: 'shepherd-theme-arrows',
      },
    })

    document.onkeydown = function documentOnkeydown(_e) {
      const e = _e || window.event
      switch (e.which || e.keyCode) {
        case 37:
          tour.back()
          break

        case 39:
          tour.next()
          break
        default: // Note: do nothing
      }
    }

    doms.forEach(function domsForEach(dom, i) {
      const xpath = findComponentParents(dom)

      //if (!document.querySelector(xpath)) {
      //  console.log(xpath);
      //}

      if (xpath != null) {
        tour.addStep('step' + i, {
          title: 'Element xPath',
          text: xpath + '<textarea>' + dom.textContent + '</textarea>',
          classes: 'shepherd-theme-arrows admin-guide-step',
          attachTo: xpath + ' bottom',
          showCancelLink: true,
          scrollTo: true,
          when: {
            show: () => {
              dom.style.border = '2px blue dashed'
            },
            hide: () => {
              dom.style.border = 'initial'
            },
          },
        })
      }
    })

    this.setState({
      adminGuideStarted: true,
    })

    tour.start()
  }

  render() {
    const computeDialect2 = ProviderHelpers.getEntry(this.props.computeDialect2, this.state.dialect)

    const warnings = {}

    const preferences = getPreferences(this.props.computeLogin, selectn('response', computeDialect2))

    return (

        <AppFrontController preferences={preferences} warnings={warnings} />

        {/*<AuthorizationFilter filter={{
                role: ['Everything'],
                entity: selectn('response.entries[0]', dialects),
                login: this.props.computeLogin
            }}>

                    {this.intl.translate({
                        key: 'super_admin_tools',
                        default: 'Super Admin Tools',
                        case: 'words'
                    })}: <FlatButton onClick={this._startAdminGuideAssist.bind(this.props.windowPath)}
                                     disabled={this.state.adminGuideStarted} label={this.intl.translate({
                    key: 'admin_guide_assist',
                    default: 'Admin Guide Assist', case: 'words'
                })}/>
                    {(this.state.adminGuideStarted) ? this.intl.translate({
                        key: 'only_one_tour_per_page',
                        default: 'You can only run one tour per page. Navigate to another page and remember to hit \'Refresh\'',
                        case: 'first'
                    }) : ''}

            </AuthorizationFilter>*/}

    )
  }
}

// REDUX: reducers/state
const mapStateToProps = (state /*, ownProps*/) => {
  const { fvDialect, navigation, nuxeo, windowPath } = state

  const { properties } = navigation
  const { computeLogin } = nuxeo
  const { computeDialect2 } = fvDialect
  const { splitWindowPath, _windowPath } = windowPath

  return {
    computeDialect2,
    computeLogin,
    properties,
    splitWindowPath,
    windowPath: _windowPath,
  }
}

// REDUX: actions/dispatch/func
const mapDispatchToProps = {
  changeTheme,
  fetchDialect2,
  nuxeoConnect,
  getCurrentUser,
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(AppWrapper)
<commit_msg>AppWrapper: Light code refactor<commit_after>/*
Copyright 2016 First People's Cultural Council

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { Component, PropTypes } from 'react'
// import ReactDOM from 'react-dom'

// REDUX
import { connect } from 'react-redux'
import { changeTheme } from 'providers/redux/reducers/navigation'
import { nuxeoConnect, getCurrentUser } from 'providers/redux/reducers/nuxeo'
import { fetchDialect2 } from 'providers/redux/reducers/fvDialect'

import selectn from 'selectn'

import ProviderHelpers from 'common/ProviderHelpers'
// import StringHelpers from 'common/StringHelpers'
import UIHelpers from 'common/UIHelpers'

// import AuthorizationFilter from 'views/components/Document/AuthorizationFilter'

import AppFrontController from './AppFrontController'

import Shepherd from 'tether-shepherd'

// import FontIcon from 'material-ui/lib/font-icon'
// import Paper from 'material-ui/lib/paper'
// import FlatButton from 'material-ui/lib/flat-button'

import IntlService from 'views/services/intl'

// const getPosition = function getPosition() {
//   const doc = document
//   const w = window
//   let x
//   let y
//   let docEl

//   if (typeof w.pageYOffset === 'number') {
//     x = w.pageXOffset
//     y = w.pageYOffset
//   } else {
//     docEl = doc.compatMode && doc.compatMode === 'CSS1Compat' ? doc.documentElement : doc.body
//     x = docEl.scrollLeft
//     y = docEl.scrollTop
//   }
//   return { x: x, y: y }
// }

/**
 * Finds the xPath for a component, leading up to the 'app-wrapper'.
 * Used as a utility for creating Shepherd tours
 */
function findComponentParents(_el) {
  let parents = []
  let el = _el
  const originalEl = el

  if (!el.getAttribute('data-component-id')) {
    return null
  }

  while (el.parentNode) {
    el = el.parentNode

    if (el.getAttribute('id') === 'app-wrapper') {
      break
    }

    if (el.tagName) {
      const appendClass = el.className ? '.' + el.className.replace(/\s/g, '.').replace(/\:/g, '\\:') : '' // eslint-disable-line
      const appendData = el.getAttribute('data-component-id')
        ? "[data-component-id='" + el.getAttribute('data-component-id') + "']"
        : ''

      parents.push(el.tagName.toLowerCase() + appendClass + appendData)
    }
  }

  parents = parents.reverse()
  parents.push(
    originalEl.tagName.toLowerCase() + "[data-component-id='" + originalEl.getAttribute('data-component-id') + "']"
  )

  return parents.join(' ')
}

const getPreferences = function getPreferences(login, dialect) {
  const preferenceString = selectn('response.properties.preferences', login)
  const parsedPreferences = preferenceString ? JSON.parse(preferenceString) : {}
  const flattenedPreferences = {}

  for (const preferenceCat in parsedPreferences) {
    for (const preference in parsedPreferences[preferenceCat]) {
      flattenedPreferences[preference] = parsedPreferences[preferenceCat][preference]
    }
  }

  // Dialect assignment
  flattenedPreferences.primary_dialect_path = selectn('path', dialect)

  return flattenedPreferences
}

const { array, func, object, string } = PropTypes
class AppWrapper extends Component {
  intl = IntlService.instance
  intlBaseKey = 'views'

  static propTypes = {
    // REDUX: actions/dispatch/func
    changeTheme: func.isRequired,
    fetchDialect2: func.isRequired,
    getCurrentUser: func.isRequired,
    nuxeoConnect: func.isRequired,
    // REDUX: reducers/state
    computeDialect2: object.isRequired,
    computeLogin: object.isRequired,
    properties: object.isRequired,
    splitWindowPath: array.isRequired,
    windowPath: string.isRequired,
  }

  static childContextTypes = {
    muiTheme: React.PropTypes.object,
  }

  // react-redux-provide will pass context such as providers (Note: this is only needed for debugging the store atm)
  static contextTypes = {
    providers: PropTypes.object,
  }

  // TODO: The legacy context API will be removed in a future major version.
  // TODO: Use the new context API introduced with version 16.3.
  // TODO: The legacy API will continue working for all 16.x releases.
  // via: https://reactjs.org/docs/legacy-context.html

  /**
   * Pass essential context to all children
   */
  getChildContext() {
    const newContext = {
      muiTheme: this.props.properties.theme.palette,
    }

    return newContext
  }

  constructor(props, context) {
    super(props, context)

    // Connect to Nuxeo
    this.props.nuxeoConnect()
    this.props.getCurrentUser()

    this.state = {
      adminGuideStarted: false,
      dialect: null,
    }
  }

  // Force update of theme if out of sync
  // This is a fix that may be unecessary in future versions of Material-UI, React, Reat-redux-provide
  componentWillReceiveProps(nextProps) {
    if (nextProps.properties.theme.id != this.props.properties.theme.id) {
      nextProps.changeTheme(nextProps.properties.theme.id)
    }
  }

  render() {
    const _computeDialect2 = ProviderHelpers.getEntry(this.props.computeDialect2, this.state.dialect)

    const warnings = {}

    const preferences = getPreferences(this.props.computeLogin, selectn('response', _computeDialect2))

    return (

        <AppFrontController preferences={preferences} warnings={warnings} />

        {/*<AuthorizationFilter filter={{
                role: ['Everything'],
                entity: selectn('response.entries[0]', dialects),
                login: this.props.computeLogin
            }}>

                    {this.intl.translate({
                        key: 'super_admin_tools',
                        default: 'Super Admin Tools',
                        case: 'words'
                    })}: <FlatButton onClick={this._startAdminGuideAssist.bind(this.props.windowPath)}
                                     disabled={this.state.adminGuideStarted} label={this.intl.translate({
                    key: 'admin_guide_assist',
                    default: 'Admin Guide Assist', case: 'words'
                })}/>
                    {(this.state.adminGuideStarted) ? this.intl.translate({
                        key: 'only_one_tour_per_page',
                        default: 'You can only run one tour per page. Navigate to another page and remember to hit \'Refresh\'',
                        case: 'first'
                    }) : ''}

            </AuthorizationFilter>*/}

    )
  }

  // Changing a theme manually...
  /*_changeTheme(event) {
      let index = event.nativeEvent.target.selectedIndex;
      this.props.changeTheme(event.target[index].value);
    }*/

  _startAdminGuideAssist = () => {
    const doms = document.querySelectorAll('[data-component-id]')

    const tour = new Shepherd.Tour({
      defaults: {
        classes: 'shepherd-theme-arrows',
      },
    })

    document.onkeydown = function documentOnkeydown(_e) {
      const e = _e || window.event
      switch (e.which || e.keyCode) {
        case 37:
          tour.back()
          break

        case 39:
          tour.next()
          break
        default: // Note: do nothing
      }
    }

    doms.forEach(function domsForEach(dom, i) {
      const xpath = findComponentParents(dom)

      //if (!document.querySelector(xpath)) {
      //  console.log(xpath);
      //}

      if (xpath != null) {
        tour.addStep('step' + i, {
          title: 'Element xPath',
          text: xpath + '<textarea>' + dom.textContent + '</textarea>',
          classes: 'shepherd-theme-arrows admin-guide-step',
          attachTo: xpath + ' bottom',
          showCancelLink: true,
          scrollTo: true,
          when: {
            show: () => {
              dom.style.border = '2px blue dashed'
            },
            hide: () => {
              dom.style.border = 'initial'
            },
          },
        })
      }
    })

    this.setState({
      adminGuideStarted: true,
    })

    tour.start()
  }
}

// REDUX: reducers/state
const mapStateToProps = (state /*, ownProps*/) => {
  const { fvDialect, navigation, nuxeo, windowPath } = state

  const { properties } = navigation
  const { computeLogin } = nuxeo
  const { computeDialect2 } = fvDialect
  const { splitWindowPath, _windowPath } = windowPath

  return {
    computeDialect2,
    computeLogin,
    properties,
    splitWindowPath,
    windowPath: _windowPath,
  }
}

// REDUX: actions/dispatch/func
const mapDispatchToProps = {
  changeTheme,
  fetchDialect2,
  nuxeoConnect,
  getCurrentUser,
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(AppWrapper)
<|endoftext|>