<commit_before>import fs from 'fs';
import Promise from 'promise';
import github from 'github-basic';
import gethub from 'gethub';
import rimraf from 'rimraf';
import lsr from 'lsr';
import throat from 'throat';
import {pushError} from './db';

const client = github({version: 3, auth: process.env.GITHUB_BOT_TOKEN});

const readFile = Promise.denodeify(fs.readFile);
const rm = Promise.denodeify(rimraf);
const directory = __dirname + '/../temp';

// TODO: client.exists doesn't work because http-basic does not work with head requests that also support gzip
client.exists = function (owner, repo) {
  return this.get('/repos/:owner/:repo', {owner, repo}).then(
    () => true,
    () => false,
  );
};

function codemodRepo(fullName) {
  const [owner, name] = fullName.split('/');

  return client.exists('npmcdn-to-unpkg-bot', name).then(exists => {
    if (exists) {
      return;
    }
    console.log('Code modding ' + fullName);
    return rm(directory).then(() => {
      console.log('downloading ' + fullName);
      return gethub(owner, name, 'master', directory);
    }).then(() => {
      console.log('fetched ' + fullName);
      return lsr(directory);
    }).then(entries => {
      return Promise.all(entries.map(entry => {
        if (entry.isFile()) {
          return readFile(entry.fullPath, 'utf8').then(content => {
            const newContent = content.replace(/\bnpmcdn\b/g, 'unpkg');
            if (newContent !== content) {
              return {
                path: entry.path.substr(2), // remove the `./` that entry paths start with
                content: newContent,
              };
            }
          });
        }
      }));
    }).then(updates => {
      updates = updates.filter(Boolean);
      if (updates.length === 0) {
        console.log('codemod resulted in no changes');
        return;
      }
      console.log('forking ' + fullName);
      return client.fork(owner, name).then(() => {
        return new Promise(resolve => setTimeout(resolve, 10000));
      }).then(() => {
        console.log('branching ' + fullName);
        return client.branch('npmcdn-to-unpkg-bot', name, 'master', 'npmcdn-to-unpkg');
      }).then(() => {
        console.log('committing ' + fullName);
        return client.commit('npmcdn-to-unpkg-bot', name, {
          branch: 'npmcdn-to-unpkg',
          message: 'Replace npmcdn.com with unpkg.com',
          updates,
        });
      }).then(() => {
        console.log('submitting pull request ' + fullName);
        return client.pull(
          {user: 'npmcdn-to-unpkg-bot', repo: name, branch: 'npmcdn-to-unpkg'},
          {user: owner, repo: name},
          {
            title: 'Replace npmcdn.com with unpkg.com',
            body: (
              'To avoid potential naming conflicts with npm, npmcdn.com is being renamed to unpkg.com. This is an ' +
              'automated pull request to update your project to use the new domain.'
            ),
          },
        );
      }).then(() => {
        console.log('codemod complete');
      });
    });
  }).then(null, err => {
    console.error('Error processing ' + fullName);
    console.error(err.stack);
    return pushError(owner, name, err.message || err);
  });
}

// only allow codemodding one repo at a time
export default throat(Promise)(1, codemodRepo);
<commit_msg>Blacklist qdot/gecko-hg<commit_after>import fs from 'fs';
import Promise from 'promise';
import github from 'github-basic';
import gethub from 'gethub';
import rimraf from 'rimraf';
import lsr from 'lsr';
import throat from 'throat';
import {pushError} from './db';

const client = github({version: 3, auth: process.env.GITHUB_BOT_TOKEN});

const readFile = Promise.denodeify(fs.readFile);
const rm = Promise.denodeify(rimraf);
const directory = __dirname + '/../temp';

// TODO: client.exists doesn't work because http-basic does not work with head requests that also support gzip
client.exists = function (owner, repo) {
  return this.get('/repos/:owner/:repo', {owner, repo}).then(
    () => true,
    () => false,
  );
};

const blackList = ['qdot/gecko-hg'];
function codemodRepo(fullName) {
  if (blackList.includes(fullName)) {
    return Promise.resolve(null);
  }
  const [owner, name] = fullName.split('/');

  return client.exists('npmcdn-to-unpkg-bot', name).then(exists => {
    if (exists) {
      return;
    }
    console.log('Code modding ' + fullName);
    return rm(directory).then(() => {
      console.log('downloading ' + fullName);
      return gethub(owner, name, 'master', directory);
    }).then(() => {
      console.log('fetched ' + fullName);
      return lsr(directory);
    }).then(entries => {
      return Promise.all(entries.map(entry => {
        if (entry.isFile()) {
          return readFile(entry.fullPath, 'utf8').then(content => {
            const newContent = content.replace(/\bnpmcdn\b/g, 'unpkg');
            if (newContent !== content) {
              return {
                path: entry.path.substr(2), // remove the `./` that entry paths start with
                content: newContent,
              };
            }
          });
        }
      }));
    }).then(updates => {
      updates = updates.filter(Boolean);
      if (updates.length === 0) {
        console.log('codemod resulted in no changes');
        return;
      }
      console.log('forking ' + fullName);
      return client.fork(owner, name).then(() => {
        return new Promise(resolve => setTimeout(resolve, 10000));
      }).then(() => {
        console.log('branching ' + fullName);
        return client.branch('npmcdn-to-unpkg-bot', name, 'master', 'npmcdn-to-unpkg');
      }).then(() => {
        console.log('committing ' + fullName);
        return client.commit('npmcdn-to-unpkg-bot', name, {
          branch: 'npmcdn-to-unpkg',
          message: 'Replace npmcdn.com with unpkg.com',
          updates,
        });
      }).then(() => {
        console.log('submitting pull request ' + fullName);
        return client.pull(
          {user: 'npmcdn-to-unpkg-bot', repo: name, branch: 'npmcdn-to-unpkg'},
          {user: owner, repo: name},
          {
            title: 'Replace npmcdn.com with unpkg.com',
            body: (
              'To avoid potential naming conflicts with npm, npmcdn.com is being renamed to unpkg.com. This is an ' +
              'automated pull request to update your project to use the new domain.'
            ),
          },
        );
      }).then(() => {
        console.log('codemod complete');
      });
    });
  }).then(null, err => {
    console.error('Error processing ' + fullName);
    console.error(err.stack);
    return pushError(owner, name, err.message || err);
  });
}

// only allow codemodding one repo at a time
export default throat(Promise)(1, codemodRepo);
<|endoftext|>


<commit_before>/* jshint esversion: 6 */

const nThen = require('nthen');
const Crypto = require('crypto');
const WriteQueue = require("./write-queue");
const BatchRead = require("./batch-read");
const RPC = require("./rpc");
const HK = require("./hk-util.js");
const Core = require("./commands/core");

const Store = require("./storage/file");
const BlobStore = require("./storage/blob");

module.exports.create = function (config, cb) {
    const Log = config.log;
    var WARN = function (e, output) {
        if (e && output) {
            Log.warn(e, {
                output: output,
                message: String(e),
                stack: new Error(e).stack,
            });
        }
    };

    Log.silly('HK_LOADING', 'LOADING HISTORY_KEEPER MODULE');

    // TODO populate Env with everything that you use from config
    // so that you can stop passing around your raw config
    // and more easily share state between historyKeeper and rpc
    const Env = {
        Log: Log,
        // tasks
        // store
        id: Crypto.randomBytes(8).toString('hex'),

        metadata_cache: {},
        channel_cache: {},
        queueStorage: WriteQueue(),
        batchIndexReads: BatchRead("HK_GET_INDEX"),
        batchMetadata: BatchRead('GET_METADATA'),

        //historyKeeper: config.historyKeeper,
        intervals: config.intervals || {},
        maxUploadSize: config.maxUploadSize || (20 * 1024 * 1024),
        Sessions: {},
        paths: {},
        //msgStore: config.store,

        netfluxUsers: {},

        pinStore: undefined,
        pinnedPads: {},
        pinsLoaded: false,
        pendingPinInquiries: {},
        pendingUnpins: {},
        pinWorkers: 5,

        limits: {},
        admins: [],
        WARN: WARN,
        flushCache: config.flushCache,
        adminEmail: config.adminEmail,
        allowSubscriptions: config.allowSubscriptions,
        myDomain: config.myDomain,
        mySubdomain: config.mySubdomain,
        customLimits: config.customLimits,
        // FIXME this attribute isn't in the default conf
        // but it is referenced in Quota
        domain: config.domain
    };

    var paths = Env.paths;

    var keyOrDefaultString = function (key, def) {
        return typeof(config[key]) === 'string'? config[key]: def;
    };

    var pinPath = paths.pin = keyOrDefaultString('pinPath', './pins');
    paths.block = keyOrDefaultString('blockPath', './block');
    paths.data = keyOrDefaultString('filePath', './datastore');
    paths.staging = keyOrDefaultString('blobStagingPath', './blobstage');
    paths.blob = keyOrDefaultString('blobPath', './blob');

    Env.defaultStorageLimit = typeof(config.defaultStorageLimit) === 'number' && config.defaultStorageLimit > 0?
        config.defaultStorageLimit:
        Core.DEFAULT_LIMIT;

    try {
        Env.admins = (config.adminKeys || []).map(function (k) {
            k = k.replace(/\/+$/, '');
            var s = k.split('/');
            return s[s.length-1];
        });
    } catch (e) {
        console.error("Can't parse admin keys. Please update or fix your config.js file!");
    }

    config.historyKeeper = Env.historyKeeper = {
        metadata_cache: Env.metadata_cache,
        channel_cache: Env.channel_cache,

        id: Env.id,

        channelMessage: function (Server, channel, msgStruct) {
            // netflux-server emits 'channelMessage' events whenever someone broadcasts to a channel
            // historyKeeper stores these messages if the channel id indicates that they are
            // a channel type with permanent history
            HK.onChannelMessage(Env, Server, channel, msgStruct);
        },
        channelClose: function (channelName) {
            // netflux-server emits 'channelClose' events whenever everyone leaves a channel
            // we drop cached metadata and indexes at the same time
            HK.dropChannel(Env, channelName);
        },
        channelOpen: function (Server, channelName, userId, wait) {
            Env.channel_cache[channelName] = Env.channel_cache[channelName] || {};

            var next = wait();
            var cb = function (err, info) {
                next(err, info, function () {
                    Server.send(userId, [
                        0,
                        Env.id,
                        'JOIN',
                        channelName
                    ]);
                });
            };

            // only conventional channels can be restricted
            if ((channelName || "").length !== HK.STANDARD_CHANNEL_LENGTH) {
                return void cb();
            }

            // gets and caches the metadata...
            // XXX make sure it doesn't get stuck in cache...
            HK.getMetadata(Env, channelName, function (err, metadata) {
                if (err) {
                    console.log("> METADATA ERR", err);
                    throw new Error(err); // XXX
                }

                if (!metadata || (metadata && !metadata.restricted)) {
                    // the channel doesn't have metadata, or it does and it's not restricted
                    // either way, let them join.
                    return void cb();
                }

                // this channel is restricted. verify that the user in question is in the allow list

                // construct a definitive list (owners + allowed)
                var allowed = HK.listAllowedUsers(metadata);
                // and get the list of keys for which this user has already authenticated
                var session = HK.getNetfluxSession(Env, userId);

                if (HK.isUserSessionAllowed(allowed, session)) {
                    return void cb();
                }

                // otherwise they're not allowed.
                // respond with a special error that includes the list of keys
                // which would be allowed...
                // XXX bonus points if you hash the keys to limit data exposure
                cb("ERESTRICTED", allowed);
            });
        },
        sessionClose: function (userId, reason) {
            HK.closeNetfluxSession(Env, userId);

            // XXX RESTRICT drop user session data
            if (['BAD_MESSAGE', 'SOCKET_ERROR', 'SEND_MESSAGE_FAIL_2'].indexOf(reason) !== -1) {
                if (reason && reason.code === 'ECONNRESET') { return; }
                return void Log.error('SESSION_CLOSE_WITH_ERROR', {
                    userId: userId,
                    reason: reason,
                });
            }

            if (reason && reason === 'SOCKET_CLOSED') { return; }
            Log.verbose('SESSION_CLOSE_ROUTINE', {
                userId: userId,
                reason: reason,
            });
        },
        directMessage: function (Server, seq, userId, json) {
            // netflux-server allows you to register an id with a handler
            // this handler is invoked every time someone sends a message to that id
            HK.onDirectMessage(Env, Server, seq, userId, json);
        },
    };

    Log.verbose('HK_ID', 'History keeper ID: ' + Env.id);

    nThen(function (w) {
        // create a pin store
        Store.create({
            filePath: pinPath,
        }, w(function (s) {
            Env.pinStore = s;
        }));

        // create a channel store
        Store.create(config, w(function (_store) {
            config.store = _store;
            Env.msgStore = _store; // API used by rpc
            Env.store = _store; // API used by historyKeeper
        }));

        // create a blob store
        BlobStore.create({
            blobPath: config.blobPath,
            blobStagingPath: config.blobStagingPath,
            archivePath: config.archivePath,
            getSession: function (safeKey) {
                return Core.getSession(Env.Sessions, safeKey);
            },
        }, w(function (err, blob) {
            if (err) { throw new Error(err); }
            Env.blobStore = blob;
        }));
    }).nThen(function (w) {
        // create a task store
        require("./storage/tasks").create(config, w(function (e, tasks) {
            if (e) {
                throw e;
            }
            Env.tasks = tasks;
            config.tasks = tasks;
            if (config.disableIntegratedTasks) { return; }

            config.intervals = config.intervals || {};
            config.intervals.taskExpiration = setInterval(function () {
                tasks.runAll(function (err) {
                    if (err) {
                        // either TASK_CONCURRENCY or an error with tasks.list
                        // in either case it is already logged.
                    }
                });
            }, 1000 * 60 * 5); // run every five minutes
        }));
    }).nThen(function () {
        RPC.create(Env, function (err, _rpc) {
            if (err) { throw err; }

            Env.rpc = _rpc;
            cb(void 0, config.historyKeeper);
        });
    });
};
<commit_msg>add backwards compatibility with older servers<commit_after>/* jshint esversion: 6 */

const nThen = require('nthen');
const Crypto = require('crypto');
const WriteQueue = require("./write-queue");
const BatchRead = require("./batch-read");
const RPC = require("./rpc");
const HK = require("./hk-util.js");
const Core = require("./commands/core");

const Store = require("./storage/file");
const BlobStore = require("./storage/blob");

module.exports.create = function (config, cb) {
    const Log = config.log;
    var WARN = function (e, output) {
        if (e && output) {
            Log.warn(e, {
                output: output,
                message: String(e),
                stack: new Error(e).stack,
            });
        }
    };

    Log.silly('HK_LOADING', 'LOADING HISTORY_KEEPER MODULE');

    // TODO populate Env with everything that you use from config
    // so that you can stop passing around your raw config
    // and more easily share state between historyKeeper and rpc
    const Env = {
        Log: Log,
        // tasks
        // store
        id: Crypto.randomBytes(8).toString('hex'),

        metadata_cache: {},
        channel_cache: {},
        queueStorage: WriteQueue(),
        batchIndexReads: BatchRead("HK_GET_INDEX"),
        batchMetadata: BatchRead('GET_METADATA'),

        //historyKeeper: config.historyKeeper,
        intervals: config.intervals || {},
        maxUploadSize: config.maxUploadSize || (20 * 1024 * 1024),
        Sessions: {},
        paths: {},
        //msgStore: config.store,

        netfluxUsers: {},

        pinStore: undefined,
        pinnedPads: {},
        pinsLoaded: false,
        pendingPinInquiries: {},
        pendingUnpins: {},
        pinWorkers: 5,

        limits: {},
        admins: [],
        WARN: WARN,
        flushCache: config.flushCache,
        adminEmail: config.adminEmail,
        allowSubscriptions: config.allowSubscriptions,
        myDomain: config.myDomain,
        mySubdomain: config.mySubdomain,
        customLimits: config.customLimits,
        // FIXME this attribute isn't in the default conf
        // but it is referenced in Quota
        domain: config.domain
    };

    var paths = Env.paths;

    var keyOrDefaultString = function (key, def) {
        return typeof(config[key]) === 'string'? config[key]: def;
    };

    var pinPath = paths.pin = keyOrDefaultString('pinPath', './pins');
    paths.block = keyOrDefaultString('blockPath', './block');
    paths.data = keyOrDefaultString('filePath', './datastore');
    paths.staging = keyOrDefaultString('blobStagingPath', './blobstage');
    paths.blob = keyOrDefaultString('blobPath', './blob');

    Env.defaultStorageLimit = typeof(config.defaultStorageLimit) === 'number' && config.defaultStorageLimit > 0?
        config.defaultStorageLimit:
        Core.DEFAULT_LIMIT;

    try {
        Env.admins = (config.adminKeys || []).map(function (k) {
            k = k.replace(/\/+$/, '');
            var s = k.split('/');
            return s[s.length-1];
        });
    } catch (e) {
        console.error("Can't parse admin keys. Please update or fix your config.js file!");
    }

    config.historyKeeper = Env.historyKeeper = {
        metadata_cache: Env.metadata_cache,
        channel_cache: Env.channel_cache,

        id: Env.id,

        channelMessage: function (Server, channel, msgStruct) {
            // netflux-server emits 'channelMessage' events whenever someone broadcasts to a channel
            // historyKeeper stores these messages if the channel id indicates that they are
            // a channel type with permanent history
            HK.onChannelMessage(Env, Server, channel, msgStruct);
        },
        channelClose: function (channelName) {
            // netflux-server emits 'channelClose' events whenever everyone leaves a channel
            // we drop cached metadata and indexes at the same time
            HK.dropChannel(Env, channelName);
        },
        channelOpen: function (Server, channelName, userId, wait) {
            Env.channel_cache[channelName] = Env.channel_cache[channelName] || {};

            var sendHKJoinMessage = function () {
                Server.send(userId, [
                    0,
                    Env.id,
                    'JOIN',
                    channelName
                ]);
            };

            // a little backwards compatibility in case you don't have the latest server
            // allow lists won't work unless you update, though
            if (typeof(wait) !== 'function') { return void sendHKJoinMessage(); }

            var next = wait();
            var cb = function (err, info) {
                next(err, info, sendHKJoinMessage);
            };

            // only conventional channels can be restricted
            if ((channelName || "").length !== HK.STANDARD_CHANNEL_LENGTH) {
                return void cb();
            }

            // gets and caches the metadata...
            // XXX make sure it doesn't get stuck in cache...
            HK.getMetadata(Env, channelName, function (err, metadata) {
                if (err) {
                    console.log("> METADATA ERR", err);
                    throw new Error(err); // XXX
                }

                if (!metadata || (metadata && !metadata.restricted)) {
                    // the channel doesn't have metadata, or it does and it's not restricted
                    // either way, let them join.
                    return void cb();
                }

                // this channel is restricted. verify that the user in question is in the allow list

                // construct a definitive list (owners + allowed)
                var allowed = HK.listAllowedUsers(metadata);
                // and get the list of keys for which this user has already authenticated
                var session = HK.getNetfluxSession(Env, userId);

                if (HK.isUserSessionAllowed(allowed, session)) {
                    return void cb();
                }

                // otherwise they're not allowed.
                // respond with a special error that includes the list of keys
                // which would be allowed...
                // XXX bonus points if you hash the keys to limit data exposure
                cb("ERESTRICTED", allowed);
            });
        },
        sessionClose: function (userId, reason) {
            HK.closeNetfluxSession(Env, userId);

            // XXX RESTRICT drop user session data
            if (['BAD_MESSAGE', 'SOCKET_ERROR', 'SEND_MESSAGE_FAIL_2'].indexOf(reason) !== -1) {
                if (reason && reason.code === 'ECONNRESET') { return; }
                return void Log.error('SESSION_CLOSE_WITH_ERROR', {
                    userId: userId,
                    reason: reason,
                });
            }

            if (reason && reason === 'SOCKET_CLOSED') { return; }
            Log.verbose('SESSION_CLOSE_ROUTINE', {
                userId: userId,
                reason: reason,
            });
        },
        directMessage: function (Server, seq, userId, json) {
            // netflux-server allows you to register an id with a handler
            // this handler is invoked every time someone sends a message to that id
            HK.onDirectMessage(Env, Server, seq, userId, json);
        },
    };

    Log.verbose('HK_ID', 'History keeper ID: ' + Env.id);

    nThen(function (w) {
        // create a pin store
        Store.create({
            filePath: pinPath,
        }, w(function (s) {
            Env.pinStore = s;
        }));

        // create a channel store
        Store.create(config, w(function (_store) {
            config.store = _store;
            Env.msgStore = _store; // API used by rpc
            Env.store = _store; // API used by historyKeeper
        }));

        // create a blob store
        BlobStore.create({
            blobPath: config.blobPath,
            blobStagingPath: config.blobStagingPath,
            archivePath: config.archivePath,
            getSession: function (safeKey) {
                return Core.getSession(Env.Sessions, safeKey);
            },
        }, w(function (err, blob) {
            if (err) { throw new Error(err); }
            Env.blobStore = blob;
        }));
    }).nThen(function (w) {
        // create a task store
        require("./storage/tasks").create(config, w(function (e, tasks) {
            if (e) {
                throw e;
            }
            Env.tasks = tasks;
            config.tasks = tasks;
            if (config.disableIntegratedTasks) { return; }

            config.intervals = config.intervals || {};
            config.intervals.taskExpiration = setInterval(function () {
                tasks.runAll(function (err) {
                    if (err) {
                        // either TASK_CONCURRENCY or an error with tasks.list
                        // in either case it is already logged.
                    }
                });
            }, 1000 * 60 * 5); // run every five minutes
        }));
    }).nThen(function () {
        RPC.create(Env, function (err, _rpc) {
            if (err) { throw err; }

            Env.rpc = _rpc;
            cb(void 0, config.historyKeeper);
        });
    });
};
<|endoftext|>


<commit_before>/*
 *
 * (c) Copyright Ascensio System Limited 2010-2017
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
*/
/**
 *    CellEdit.js
 *
 *    Created by Maxim Kadushkin on 04 April 2014
 *    Copyright (c) 2014 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'text!spreadsheeteditor/main/app/template/CellEditor.template',
    'common/main/lib/component/BaseView'
], function (template) {
    'use strict';

    SSE.Views.CellEditor = Common.UI.BaseView.extend(_.extend({
        template: _.template(template),

        initialize: function (options) {
            Common.UI.BaseView.prototype.initialize.call(this, options);
        },

        render: function () {
            $(this.el).html(this.template());

            this.btnNamedRanges = new Common.UI.Button({
                menu        : new Common.UI.Menu({
                    style   : 'min-width: 70px;max-width:400px;',
                    maxHeight: 250,
                    items: [
                        { caption: this.textManager, value: 'manager' },
                        { caption: '--' }
                    ]
                }).on('render:after', function(mnu) {
                        this.scroller = new Common.UI.Scroller({
                        el: $(this.el).find('.dropdown-menu '),
                        useKeyboard: this.enableKeyEvents && !this.handleSelect,
                        minScrollbarLength  : 40
                    });
                }).on('show:after', function () {
                    this.scroller.update({alwaysVisibleY: true});
                })
            });
            this.btnNamedRanges.render($('#ce-cell-name-menu'));
            this.btnNamedRanges.setVisible(false);
            this.btnNamedRanges.menu.setOffset(-81);

            this.$cellname = $('#ce-cell-name', this.el);
            this.$btnexpand = $('#ce-btn-expand', this.el);
            this.$btnfunc = $('#ce-func-label', this.el);

            var me = this;
            this.$cellname.on('focusin', function(e){
                me.$cellname.select().one('mouseup', function (e) {e.preventDefault();});
            });

            this.$btnfunc.addClass('disabled');
            this.$btnfunc.tooltip({
                title       : this.tipFormula,
                placement   : 'cursor'
            });

            return this;
        },

        updateCellInfo: function(info) {
            if (info) {
                this.$cellname.val(typeof(info)=='string' ? info : info.asc_getName());
            }
        },

        cellNameDisabled: function(disabled){
            (disabled) ? this.$cellname.attr('disabled', 'disabled') : this.$cellname.removeAttr('disabled');
            this.btnNamedRanges.setDisabled(disabled);
        },

        tipFormula: 'Insert Function',
        textManager: 'Manager'
    }, SSE.Views.CellEditor || {}));
});
<commit_msg>[SSE] Fix Bug 37041<commit_after>/*
 *
 * (c) Copyright Ascensio System Limited 2010-2017
 *
 * This program is a free software product. You can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License (AGPL)
 * version 3 as published by the Free Software Foundation. In accordance with
 * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
 * that Ascensio System SIA expressly excludes the warranty of non-infringement
 * of any third-party rights.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE. For
 * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
 *
 * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * The  interactive user interfaces in modified source and object code versions
 * of the Program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU AGPL version 3.
 *
 * Pursuant to Section 7(b) of the License you must retain the original Product
 * logo when distributing the program. Pursuant to Section 7(e) we decline to
 * grant you any rights under trademark law for use of our trademarks.
 *
 * All the Product's GUI elements, including illustrations and icon sets, as
 * well as technical writing content are licensed under the terms of the
 * Creative Commons Attribution-ShareAlike 4.0 International. See the License
 * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
 *
*/
/**
 *    CellEdit.js
 *
 *    Created by Maxim Kadushkin on 04 April 2014
 *    Copyright (c) 2014 Ascensio System SIA. All rights reserved.
 *
 */

define([
    'text!spreadsheeteditor/main/app/template/CellEditor.template',
    'common/main/lib/component/BaseView'
], function (template) {
    'use strict';

    SSE.Views.CellEditor = Common.UI.BaseView.extend(_.extend({
        template: _.template(template),

        initialize: function (options) {
            Common.UI.BaseView.prototype.initialize.call(this, options);
        },

        render: function () {
            $(this.el).html(this.template());

            this.btnNamedRanges = new Common.UI.Button({
                menu        : new Common.UI.Menu({
                    style   : 'min-width: 70px;max-width:400px;',
                    maxHeight: 250,
                    items: [
                        { caption: this.textManager, value: 'manager' },
                        { caption: '--' }
                    ]
                }).on('render:after', function(mnu) {
                        this.scroller = new Common.UI.Scroller({
                        el: $(this.el).find('.dropdown-menu '),
                        useKeyboard: this.enableKeyEvents && !this.handleSelect,
                        minScrollbarLength  : 40
                    });
                }).on('show:after', function () {
                    this.scroller.update({alwaysVisibleY: true});
                })
            });
            this.btnNamedRanges.render($('#ce-cell-name-menu'));
            this.btnNamedRanges.setVisible(false);
            this.btnNamedRanges.menu.setOffset(-81);

            this.$cellname = $('#ce-cell-name', this.el);
            this.$btnexpand = $('#ce-btn-expand', this.el);
            this.$btnfunc = $('#ce-func-label', this.el);

            var me = this;
            this.$cellname.on('focus', function(e){
                var txt = me.$cellname[0];
                txt.selectionStart = 0;
                txt.selectionEnd = txt.value.length;
                txt.scrollLeft = txt.scrollWidth;
            });

            this.$btnfunc.addClass('disabled');
            this.$btnfunc.tooltip({
                title       : this.tipFormula,
                placement   : 'cursor'
            });

            return this;
        },

        updateCellInfo: function(info) {
            if (info) {
                this.$cellname.val(typeof(info)=='string' ? info : info.asc_getName());
            }
        },

        cellNameDisabled: function(disabled){
            (disabled) ? this.$cellname.attr('disabled', 'disabled') : this.$cellname.removeAttr('disabled');
            this.btnNamedRanges.setDisabled(disabled);
        },

        tipFormula: 'Insert Function',
        textManager: 'Manager'
    }, SSE.Views.CellEditor || {}));
});
<|endoftext|>


<commit_before>// Capability configuration for user roles.
// These define what features user can see and access.
// The role of the user is stored in JWT token the user possess.
//
module.exports = { // New in v14
  'public': [
    'geometry',
  ],
  'invited': [
    'account-signup',
  ],
  'frozen': [
    'coordinates',
    'location-read',
  ],
  'basic': [
    'account-read-own',
    'account-change-email-own',
    'account-change-password-own',
    'coordinates',
    'location-read',
    'location-create',
    'location-edit-own',
    'location-delete-own',
    'post-read',
    'post-create',
    'post-edit-own',
    'post-delete-own',
    'comment-read',
    'comment-create',
    'comment-edit-own',
    'comment-delete-own',
    'user-read',
    'search',
    'filter',
    'statistics',
  ],
  'moderator': [],
  'admin': [
    'search',
    'filter',
    'coordinates',
    'location-read',
    'location-create',
    'location-edit-own',
    'location-delete-any',
    'post-read',
    'post-create',
    'post-edit-own',
    'post-delete-any',
    'comment-read',
    'comment-create',
    'comment-edit-own',
    'comment-delete-any',
    'user-read',

    'admin',
    'account-invite',
    'account-edit',
    'statistics',
  ],
};
<commit_msg>Simplify the set of capabilities<commit_after>// Capability configuration for user roles.
// These define what features user can see and access.
// The role of the user is stored in JWT token the user possess.
//
module.exports = { // New in v14
  'public': [
    'geometry',
    'account-login',
    'account-password-reset-request',
  ],
  'invited': [
    'account-signup',
  ],
  'resetter': [
    'account-password-reset',
  ],
  'frozen': [],
  'basic': [
    'account-edit',
    'comments',
    'geometry',
    'locations',
    'posts',
    'statistics',
    'users',
  ],
  'moderator': [],
  'admin': [
    'admin',
    'account-invite',
    'account-edit',
    'comments',
    'geometry',
    'locations',
    'posts',
    'statistics',
    'users',
  ],
};
<|endoftext|>


<commit_before>var sanitizeHtml = require('sanitize-html');

var htmlSanitizer = {};

htmlSanitizer.hookConverter = function(converter) {
  converter.hooks.chain('postConversion', sanitizeHtmlCustomized);
}

function sanitizeHtmlCustomized(state) {
  var html = state.text;
  var options = {
    allowedTags: [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol', 'nl', 'li', 'b', 'i',
                   'strong', 'em', 'strike', 'code', 'hr', 'br', 'div', 'table', 'thead', 'caption', 'tbody', 'tr',
                   'th', 'td', 'pre', 'img', 'style', 'iframe', 'del' , 'dl', 'dt', 'dd', 'defs'],
    allowedAttributes: {
      a: [ 'href', 'name', 'target', 'data-widget-id' ],
      // We don't currently allow img itself by default, but this
      // would make sense if we did
      div: ['align', 'data-href', 'data-layout', 'data-action', 'data-show-faces', 'data-share', 'data-width', 'data-height'],
      img: [ 'src' , 'width', 'height'],
      iframe: ['width', 'height', 'src', 'frameborder', 'allowfullscreen'],
      code: ['class'],
      td: ['align', 'style'],
      th: ['align', 'style']
    },
    // Lots of these won't come up by default because we don't allow them
    selfClosing: [ 'img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta' ],
    // URL schemes we permit
    allowedSchemes: [ 'http', 'https', 'ftp', 'mailto' ],
    // Be more specific about allowed schemes
    // for a certain tag
    allowedSchemesByTag: {
      img: [ 'http', 'https' ]
    },
    allowedClasses: {
      a: [ 'twitter-timeline', 'twitter-share-button' ],
      div: [ 'fb-follow', 'fb-like' ],
      img: [ 'centered' ],
      svg: [ 'centered' ],
      iframe: [ 'centered' ]
    }
  };
  var svg = {'svg': [ 'width', 'height', 'style', 'viewbox', 'xmlns', 'xmlns:xlink', 'version' ],
             'circle': [ 'r', 'cx', 'cy', 'style' ],
             'ellipse': [ 'rx', 'ry', 'cx', 'cy', 'style' ],
             'polygon': [ 'points', 'style' ],
             'polyline': [ 'points', 'style' ],
             'text': [ 'x', 'y', 'dx', 'dy', 'style' ],
             'path': [ 'd' ,'style' ],
             'g': [ 'transform' ,'style', 'id' ],
             'use': [ 'xlink:href' ],
             'line': [ 'x1', 'y1', 'x2', 'y2', 'style' ],
             'rect': [ 'x', 'y', 'width', 'height', 'style' ]};
  options.allowedTags = options.allowedTags.concat(Object.keys(svg));
  for (var key in svg) options.allowedAttributes[key] = svg[key];
  state.text = sanitizeHtml(html, options)
  return state;
}

module.exports = htmlSanitizer;
<commit_msg>allowed modification of width and height of images<commit_after>var sanitizeHtml = require('sanitize-html');

var htmlSanitizer = {};

htmlSanitizer.hookConverter = function(converter) {
  converter.hooks.chain('postConversion', sanitizeHtmlCustomized);
}

function sanitizeHtmlCustomized(state) {
  var html = state.text;
  var options = {
    allowedTags: [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol', 'nl', 'li', 'b', 'i',
                   'strong', 'em', 'strike', 'code', 'hr', 'br', 'div', 'table', 'thead', 'caption', 'tbody', 'tr',
                   'th', 'td', 'pre', 'img', 'style', 'iframe', 'del' , 'dl', 'dt', 'dd', 'defs'],
    allowedAttributes: {
      a: [ 'href', 'name', 'target', 'data-widget-id' ],
      // We don't currently allow img itself by default, but this
      // would make sense if we did
      div: ['align', 'data-href', 'data-layout', 'data-action', 'data-show-faces', 'data-share', 'data-width', 'data-height'],
      img: [ 'src' , 'width', 'height', 'max-width', 'max-height'],
      iframe: ['width', 'height', 'src', 'frameborder', 'allowfullscreen'],
      code: ['class'],
      td: ['align', 'style'],
      th: ['align', 'style']
    },
    // Lots of these won't come up by default because we don't allow them
    selfClosing: [ 'img', 'br', 'hr', 'area', 'base', 'basefont', 'input', 'link', 'meta' ],
    // URL schemes we permit
    allowedSchemes: [ 'http', 'https', 'ftp', 'mailto' ],
    // Be more specific about allowed schemes
    // for a certain tag
    allowedSchemesByTag: {
      img: [ 'http', 'https' ]
    },
    allowedClasses: {
      a: [ 'twitter-timeline', 'twitter-share-button' ],
      div: [ 'fb-follow', 'fb-like' ],
      img: [ 'centered' ],
      svg: [ 'centered' ],
      iframe: [ 'centered' ]
    }
  };
  var svg = {'svg': [ 'width', 'height', 'style', 'viewbox', 'xmlns', 'xmlns:xlink', 'version' ],
             'circle': [ 'r', 'cx', 'cy', 'style' ],
             'ellipse': [ 'rx', 'ry', 'cx', 'cy', 'style' ],
             'polygon': [ 'points', 'style' ],
             'polyline': [ 'points', 'style' ],
             'text': [ 'x', 'y', 'dx', 'dy', 'style' ],
             'path': [ 'd' ,'style' ],
             'g': [ 'transform' ,'style', 'id' ],
             'use': [ 'xlink:href' ],
             'line': [ 'x1', 'y1', 'x2', 'y2', 'style' ],
             'rect': [ 'x', 'y', 'width', 'height', 'style' ]};
  options.allowedTags = options.allowedTags.concat(Object.keys(svg));
  for (var key in svg) options.allowedAttributes[key] = svg[key];
  state.text = sanitizeHtml(html, options)
  return state;
}

module.exports = htmlSanitizer;
<|endoftext|>


<commit_before>'use strict';
var fs = require('fs');
var _path = require('path');

var mkdirp = require('mkdirp');
var ncp = require('ncp');
var webpack = require('webpack');
var webpackConfig = require('./webpack.coffee').build;

exports.buildDevIndex = function(config) {
  process.env.NODE_ENV = 'dev';

  webpack(webpackConfig(config), function(err) {
    if(err) {
      return console.error(err);
    }

    var cwd = process.cwd();
    var page = require(_path.join(cwd, './.antwar/build/bundleStaticPage.js'));

    fs.writeFileSync(
      _path.join(cwd, './.antwar/build/index.html'),
      page,
      '/antwar_devindex',
      null
    );

    ncp('./assets', _path.join(cwd, './.antwar/build/assets'));
  });
};

exports.build = function(config) {
  process.env.NODE_ENV = 'production';

  webpack(webpackConfig(config), function(err) {
    if(err) {
      return console.error(err);
    }

    var cwd = process.cwd();

    var assets = _path.join(cwd, './public/assets');
    var renderPage = require(_path.join(cwd, './.antwar/build/bundleStaticPage.js'));
    var paths = require(_path.join(cwd, './.antwar/build/paths.js'));

    mkdirp.sync(_path.join(cwd, './public/blog'));
    mkdirp.sync(assets);

    ncp(_path.join(cwd, './assets'), assets);

    fs.writeFileSync(
      _path.join(assets, '/main.css'),
      fs.readFileSync('./.antwar/build/main.css')
    );

    var allPaths = paths();
    writePages(cwd, renderPage, allPaths);
    writeIndex(cwd, renderPage);
    writePosts(cwd, renderPage, allPaths);

    // TODO: this should be pushed to a plugin
    //var rss = require(_path.join(cwd, './.antwar/build/bundleStaticRss.js'));
    //fs.writeFileSync(_path.join(process.cwd(), './public/atom.xml'), rss(renderPage));
  });
};

function writePages(root, renderPage, allPaths) {
  Object.keys(allPaths).forEach(function(path) {
    if(path !== 'posts') {
      var publicPath;

      if(path === '/') {
        path = '';

        publicPath = _path.join(root, './public');
      }
      else {
        publicPath = _path.join(root, './public/#' + path);

        mkdirp.sync(publicPath);
      }

      fs.writeFileSync(
        _path.join(publicPath, 'index.html'),
        renderPage('/#' + path, null)
      );
    }
  });
}

function writeIndex(root, renderPage) {
  fs.writeFileSync(
    _path.join(root, './public/blog/index.html'),
    renderPage('/blog', null)
  );
}

function writePosts(root, renderPage, allPaths) {
  Object.keys(allPaths.posts).forEach(function(post) {
    fs.writeFileSync(
      _path.join(root, './public/blog/' + post + '.html'),
      renderPage('/blog' + post)
    );
  });
}
<commit_msg>Don't write CSS<commit_after>'use strict';
var fs = require('fs');
var _path = require('path');

var mkdirp = require('mkdirp');
var ncp = require('ncp');
var webpack = require('webpack');
var webpackConfig = require('./webpack.coffee').build;

exports.buildDevIndex = function(config) {
  process.env.NODE_ENV = 'dev';

  webpack(webpackConfig(config), function(err) {
    if(err) {
      return console.error(err);
    }

    var cwd = process.cwd();
    var page = require(_path.join(cwd, './.antwar/build/bundleStaticPage.js'));

    fs.writeFileSync(
      _path.join(cwd, './.antwar/build/index.html'),
      page,
      '/antwar_devindex',
      null
    );

    ncp('./assets', _path.join(cwd, './.antwar/build/assets'));
  });
};

exports.build = function(config) {
  process.env.NODE_ENV = 'production';

  webpack(webpackConfig(config), function(err) {
    if(err) {
      return console.error(err);
    }

    var cwd = process.cwd();

    var assets = _path.join(cwd, './public/assets');
    var renderPage = require(_path.join(cwd, './.antwar/build/bundleStaticPage.js'));
    var paths = require(_path.join(cwd, './.antwar/build/paths.js'));

    mkdirp.sync(_path.join(cwd, './public/blog'));
    mkdirp.sync(assets);

    ncp(_path.join(cwd, './assets'), assets);

    // TODO: write CSS if it exists
    /*
    fs.writeFileSync(
      _path.join(assets, '/main.css'),
      fs.readFileSync('./.antwar/build/main.css')
    );
    */

    var allPaths = paths();
    writePages(cwd, renderPage, allPaths);
    writeIndex(cwd, renderPage);
    writePosts(cwd, renderPage, allPaths);

    // TODO: this should be pushed to a plugin
    //var rss = require(_path.join(cwd, './.antwar/build/bundleStaticRss.js'));
    //fs.writeFileSync(_path.join(process.cwd(), './public/atom.xml'), rss(renderPage));
  });
};

function writePages(root, renderPage, allPaths) {
  Object.keys(allPaths).forEach(function(path) {
    if(path !== 'posts') {
      var publicPath;

      if(path === '/') {
        path = '';

        publicPath = _path.join(root, './public');
      }
      else {
        publicPath = _path.join(root, './public/#' + path);

        mkdirp.sync(publicPath);
      }

      fs.writeFileSync(
        _path.join(publicPath, 'index.html'),
        renderPage('/#' + path, null)
      );
    }
  });
}

function writeIndex(root, renderPage) {
  fs.writeFileSync(
    _path.join(root, './public/blog/index.html'),
    renderPage('/blog', null)
  );
}

function writePosts(root, renderPage, allPaths) {
  Object.keys(allPaths.posts).forEach(function(post) {
    fs.writeFileSync(
      _path.join(root, './public/blog/' + post + '.html'),
      renderPage('/blog' + post)
    );
  });
}
<|endoftext|>


<commit_before>var path = require('path')
    , fs = require('fs')
    , _ = require('underscore')
    , async = require('async')
    , dir = path.dirname(require.main.filename) + '/output/' // path to the root
    , barstool = require('./lib/barstool')
    , sheetData
    , wstream
    , speakers = {}
    ;

// =====
// GENERAL USE UTILITIES
// =====

// Helper function not called in the build process ...
// Processes each row, outputs it with double quotes escaped and characters
// correctly transformed.
function prepareRow(row){
  return _.map(row, function(item,key){
    // Escape double quotes inside and add double quotes around each item
    return '"' +
           item
           .replace(/"/g,'\'')
           .replace(/\n/g,'')
           .replace(/[\u2018\u2019]/g, '\'')
           .replace(/[\u201C\u201D]/g, '\'')
           + '"';
  })
  .join(',')+'\n';
}

// Create our writestream to @fileName (STRING)
function openStream(cb,fileName){
  // Clear the file
  fs.writeFile(dir + fileName, '', function(){})
  // Open a writestream
  wstream = fs.createWriteStream(dir + fileName);
  cb(null);
}

// Close the open write stream
function closeStream(cb){
  wstream.end();
  cb(null);
}

// Write our headers from @headers (STRING)
function writeHeaders(cb,headers){
  wstream.write(headers);
  cb(null);
};

// Get all worksheets, assign to global-scope `sheetData` variable
function getSheetData(cb){
  barstool.getAllWorksheets(function(err,data){
    if (err) throw err;
    sheetData = data;
    cb(err);
  });
}

// =====
// PARSE AND WRITE SPECIFIC DATA
// =====

// Write the mainstage/schedule block sessions
function writePrimarySessions(cb,sheetName){
  async.eachSeries(sheetData[sheetName], function(row,callback){
    var entry = [];

    // Name (required)
    entry.push(row['sessiontitle']);
    // Description
    entry.push(row['sessiondescription']);

    // ... do some data crunching to format date ...
    var time = row['timeblock'].split(' - ');
    // Start time (required): "3/13/2014 1:11:00 PM"
    entry.push(row['date'] + ' ' + time[0]);
    // End time (required): "3/13/2014 1:11:00 PM"
    entry.push(row['date'] + ' ' + time[1]);

    // Location
    // ... we aren't using these for now ...
    entry.push('');

    // Session Tracks
    entry.push(row['sessiontype']);

    // Filters
    // ... we aren't using these for now ...
    entry.push('');

    // Speaker IDs
    var speakers = [];
    if (row['speakersafe1'].length > 0) { speakers.push(row['speakersafe1']) }
    if (row['speakersafe2'].length > 0) { speakers.push(row['speakersafe2']) }
    if (row['speakersafe3'].length > 0) { speakers.push(row['speakersafe3']) }
    if (row['speakersafe4'].length > 0) { speakers.push(row['speakersafe4']) }
    if (row['speakersafe5'].length > 0) { speakers.push(row['speakersafe5']) }
    if (row['speakersafe6'].length > 0) { speakers.push(row['speakersafe6']) }
    if (row['speakersafe7'].length > 0) { speakers.push(row['speakersafe7']) }
    entry.push(speakers.join(','));

    // Link URLs
    // ... we aren't using these for now ...
    entry.push('');

    // Session ID (unique)
    entry.push(row['sessionuniquekey']);

    // Write the prepared row
    wstream.write( prepareRow(entry) );
    callback(null);
  },function(err){ cb(err) });
}

// Write the breakout sessions
function writeBreakoutSessions(cb,sheetName){
  async.eachSeries(sheetData[sheetName], function(row,callback){
    // If the breakout isn't confirmed, pass on it
    if (row['status'] !== 'Confirmed') { callback(null); }
    else {
      // Otherwise, proceed
      var entry = [];

      // Name (required)
      entry.push(row['sessiontitle']);
      // Description
      entry.push(row['sessiondescription']);

      // ... do some data crunching to format date ...
      var time = row['timeblock'].split(' - ');
      // Start time (required): "3/13/2014 1:11:00 PM"
      entry.push(row['date'] + ' ' + time[0]);
      // End time (required): "3/13/2014 1:11:00 PM"
      entry.push(row['date'] + ' ' + time[1]);

      // Location
      // ... we aren't using these for now ...
      entry.push(row['roomlocation']);

      // Session Tracks
      entry.push(row['sessionaudience']);

      // Filters
      // ... we aren't using these for now ...
      entry.push('');

      // Speaker IDs
      var speakers = [];
      if (row['speakersafe1'].length > 0) { speakers.push(row['speakersafe1']) }
      if (row['speakersafe2'].length > 0) { speakers.push(row['speakersafe2']) }
      if (row['speakersafe3'].length > 0) { speakers.push(row['speakersafe3']) }
      if (row['speakersafe4'].length > 0) { speakers.push(row['speakersafe4']) }
      if (row['speakersafe5'].length > 0) { speakers.push(row['speakersafe5']) }
      if (row['speakersafe6'].length > 0) { speakers.push(row['speakersafe6']) }
      if (row['speakersafe7'].length > 0) { speakers.push(row['speakersafe7']) }
      entry.push(speakers.join(','));

      // Link URLs
      // ... we aren't using these for now ...
      entry.push('');

      // Session ID (unique)
      entry.push(row['sessionuniquekey']);

      // Write the prepared row
      wstream.write( prepareRow(entry) );
      callback(null);
    }
  },function(err){ cb(err) });
}

function prepSpeakers(cb,sheetName){
  async.eachSeries(sheetData[sheetName], function(row,callback){
    // How many speakers do we support?
    var numSpeakers = 7,
        count = 0;

    async.until(
      function(){ return count == numSpeakers; },
      function(callllback){
        count++;
        var speaker_key = row['speakersafe'+count];

        // If we don't have speaker, skip
        if (row['speakername'+count].length === 0) {
          return callllback(null);
        }

        // Have we already seen this speaker? If so, skip it
        if (typeof(speakers[speaker_key]) === "object") {
          return callllback(null);
        }

        // OK, we've got a speaker, so go ahead and get it ready...
        var speaker = {};

        // Grab the name and safe/key, this is easy(ish)
        var name = row['speakername'+count].replace('Dr. ','').replace('Mayor ','')

        speaker['First Name (required)'] = name.substr(0,name.indexOf(' '));
        speaker['Last Name (required)'] = name.substr(name.indexOf(' ')+1);
        speaker['Speaker ID'] = row['speakersafe'+count];

        // Get the title/org
        if ( row['speakertitleorg'+count].indexOf(',') > 0 ) {
          // If there's a comma, i.e. if there's a 'Title here, Org here', split it up
          speaker['Title'] = row['speakertitleorg'+count].substr(0,row['speakertitleorg'+count].indexOf(','));
          speaker['Company'] = row['speakertitleorg'+count].substr(row['speakertitleorg'+count].indexOf(',')+1).replace(' ','');
        } else {
          // No comma, so shove everything in the title and make org empty
          speaker['Title'] = row['speakertitleorg'+count];
          speaker['Company'] = "";
        }

        // Figure out if we can grab a link to a photo, if we can, give it
        if ( row['speakerphoto'+count] == 'STAFF' ) {
          speaker['Image URL'] = 'http://codeforamerica.org/media/images/people/' + row['speakersafe'+count] + '.jpg';
        } else if ( row['speakerphoto'+count] == 'SPEAKER' ) {
          speaker['Image URL'] = 'http://codeforamerica.org/media/images/summit/2015/speakers/thumbnails/' + row['speakersafe'+count] + '.jpg';
        } else {
          speaker['Image URL'] = "";
        }

        // Don't do this. We don't want to write session IDs.
        speaker['Session IDs'] = "";

        // ... we don't have these ...
        speaker['Description'] = "";
        speaker['Website'] = "";
        speaker['Twitter Handle'] = "";
        speaker['Facebook URL'] = "";
        speaker['LinkedIn URL'] = "";
        speaker['Attendee ID'] = "";

        // speakers.push(speaker);
        speakers[row['speakersafe'+count]] = speaker;
        callllback(null);

      },
      function(err){ callback(null); }
    );
  },function(err){
    cb(err);
  });
}

function writeSpeakers(cb){
  async.forEachOfSeries(speakers, function(value,key,callback){
    var entry = [];

    // "First Name (required)"
    entry.push(value["First Name (required)"]);
    // "Last Name (required)"
    entry.push(value["Last Name (required)"]);
    // "Title"
    entry.push(value["Title"]);
    // "Company"
    entry.push(value["Company"]);
    // "Description"
    entry.push(value["Description"]);
    // "Image URL"
    entry.push(value["Image URL"]);
    // "Website"
    entry.push(value["Website"]);
    // "Twitter Handle"
    entry.push(value["Twitter Handle"]);
    // "Facebook URL"
    entry.push(value["Facebook URL"]);
    // "LinkedIn URL"
    entry.push(value["LinkedIn URL"]);
    // "Session IDs"
    entry.push(value["Session IDs"]);
    // "Attendee ID"
    entry.push(value["Attendee ID"]);
    // "Speaker ID"
    entry.push(value["Speaker ID"]);

    // Write the prepared row
    wstream.write( prepareRow(entry) );
    callback(null);
  },
  function(err){
    cb(null);
  });
}

// =====
// PERFORM ALL THE TASKS
// =====

async.series([
  function(cb){ getSheetData(cb)
              },
  function(cb){ openStream(cb,'session-import.csv')
              },
  function(cb){ writeHeaders(cb,'"Name (required)","Description","Start Time (required)","End Time (required)","Location","Session Tracks","Filters","Speaker IDs","Link URLs","Session ID"\n')
              },
  function(cb){ writePrimarySessions(cb,'external_live_data')
              },
  function(cb){ writeBreakoutSessions(cb,'breakout_descriptions')
              },
  function(cb){ closeStream(cb)
              },
  function(cb){ openStream(cb,'speakers-import.csv')
              },
  function(cb){ writeHeaders(cb,'"First Name (required)","Last Name (required)","Title","Company","Description","Image URL","Website","Twitter Handle","Facebook URL","LinkedIn URL","Session IDs","Attendee ID","Speaker ID"\n')
              },
  function(cb){ prepSpeakers(cb,'external_live_data')
              },
  function(cb){ prepSpeakers(cb,'breakout_descriptions')
              },
  function(cb){ writeSpeakers(cb)
              },
  function(cb){ closeStream(cb)
              },
]);
<commit_msg>Strip tags in titles<commit_after>var path = require('path')
    , fs = require('fs')
    , _ = require('underscore')
    , async = require('async')
    , dir = path.dirname(require.main.filename) + '/output/' // path to the root
    , barstool = require('./lib/barstool')
    , sheetData
    , wstream
    , speakers = {}
    ;

// =====
// GENERAL USE UTILITIES
// =====

// Helper function not called in the build process ...
// Processes each row, outputs it with double quotes escaped and characters
// correctly transformed.
function prepareRow(row){
  return _.map(row, function(item,key){
    // Escape double quotes inside and add double quotes around each item
    return '"' +
           item
           .replace(/"/g,'\'')
           .replace(/\n/g,'')
           .replace(/[\u2018\u2019]/g, '\'')
           .replace(/[\u201C\u201D]/g, '\'')
           + '"';
  })
  .join(',')+'\n';
}

function stripTags(thing){
  return thing.replace(/<[^>]*>/ig, "");
}

// Create our writestream to @fileName (STRING)
function openStream(cb,fileName){
  // Clear the file
  fs.writeFile(dir + fileName, '', function(){})
  // Open a writestream
  wstream = fs.createWriteStream(dir + fileName);
  cb(null);
}

// Close the open write stream
function closeStream(cb){
  wstream.end();
  cb(null);
}

// Write our headers from @headers (STRING)
function writeHeaders(cb,headers){
  wstream.write(headers);
  cb(null);
};

// Get all worksheets, assign to global-scope `sheetData` variable
function getSheetData(cb){
  barstool.getAllWorksheets(function(err,data){
    if (err) throw err;
    sheetData = data;
    cb(err);
  });
}

// =====
// PARSE AND WRITE SPECIFIC DATA
// =====

// Write the mainstage/schedule block sessions
function writePrimarySessions(cb,sheetName){
  async.eachSeries(sheetData[sheetName], function(row,callback){
    var entry = [];

    // Name (required)
    entry.push(stripTags(row['sessiontitle']));
    // Description
    entry.push(row['sessiondescription']);

    // ... do some data crunching to format date ...
    var time = row['timeblock'].split(' - ');
    // Start time (required): "3/13/2014 1:11:00 PM"
    entry.push(row['date'] + ' ' + time[0]);
    // End time (required): "3/13/2014 1:11:00 PM"
    entry.push(row['date'] + ' ' + time[1]);

    // Location
    // ... we aren't using these for now ...
    entry.push('');

    // Session Tracks
    entry.push(row['sessiontype']);

    // Filters
    // ... we aren't using these for now ...
    entry.push('');

    // Speaker IDs
    var speakers = [];
    if (row['speakersafe1'].length > 0) { speakers.push(row['speakersafe1']) }
    if (row['speakersafe2'].length > 0) { speakers.push(row['speakersafe2']) }
    if (row['speakersafe3'].length > 0) { speakers.push(row['speakersafe3']) }
    if (row['speakersafe4'].length > 0) { speakers.push(row['speakersafe4']) }
    if (row['speakersafe5'].length > 0) { speakers.push(row['speakersafe5']) }
    if (row['speakersafe6'].length > 0) { speakers.push(row['speakersafe6']) }
    if (row['speakersafe7'].length > 0) { speakers.push(row['speakersafe7']) }
    entry.push(speakers.join(','));

    // Link URLs
    // ... we aren't using these for now ...
    entry.push('');

    // Session ID (unique)
    entry.push(row['sessionuniquekey']);

    // Write the prepared row
    wstream.write( prepareRow(entry) );
    callback(null);
  },function(err){ cb(err) });
}

// Write the breakout sessions
function writeBreakoutSessions(cb,sheetName){
  async.eachSeries(sheetData[sheetName], function(row,callback){
    // If the breakout isn't confirmed, pass on it
    if (row['status'] !== 'Confirmed') { callback(null); }
    else {
      // Otherwise, proceed
      var entry = [];

      // Name (required)
      entry.push(stripTags(row['sessiontitle']));
      // Description
      entry.push(row['sessiondescription']);

      // ... do some data crunching to format date ...
      var time = row['timeblock'].split(' - ');
      // Start time (required): "3/13/2014 1:11:00 PM"
      entry.push(row['date'] + ' ' + time[0]);
      // End time (required): "3/13/2014 1:11:00 PM"
      entry.push(row['date'] + ' ' + time[1]);

      // Location
      // ... we aren't using these for now ...
      entry.push(row['roomlocation']);

      // Session Tracks
      entry.push(row['sessionaudience']);

      // Filters
      // ... we aren't using these for now ...
      entry.push('');

      // Speaker IDs
      var speakers = [];
      if (row['speakersafe1'].length > 0) { speakers.push(row['speakersafe1']) }
      if (row['speakersafe2'].length > 0) { speakers.push(row['speakersafe2']) }
      if (row['speakersafe3'].length > 0) { speakers.push(row['speakersafe3']) }
      if (row['speakersafe4'].length > 0) { speakers.push(row['speakersafe4']) }
      if (row['speakersafe5'].length > 0) { speakers.push(row['speakersafe5']) }
      if (row['speakersafe6'].length > 0) { speakers.push(row['speakersafe6']) }
      if (row['speakersafe7'].length > 0) { speakers.push(row['speakersafe7']) }
      entry.push(speakers.join(','));

      // Link URLs
      // ... we aren't using these for now ...
      entry.push('');

      // Session ID (unique)
      entry.push(row['sessionuniquekey']);

      // Write the prepared row
      wstream.write( prepareRow(entry) );
      callback(null);
    }
  },function(err){ cb(err) });
}

function prepSpeakers(cb,sheetName){
  async.eachSeries(sheetData[sheetName], function(row,callback){
    // How many speakers do we support?
    var numSpeakers = 7,
        count = 0;

    async.until(
      function(){ return count == numSpeakers; },
      function(callllback){
        count++;
        var speaker_key = row['speakersafe'+count];

        // If we don't have speaker, skip
        if (row['speakername'+count].length === 0) {
          return callllback(null);
        }

        // Have we already seen this speaker? If so, skip it
        if (typeof(speakers[speaker_key]) === "object") {
          return callllback(null);
        }

        // OK, we've got a speaker, so go ahead and get it ready...
        var speaker = {};

        // Grab the name and safe/key, this is easy(ish)
        var name = row['speakername'+count].replace('Dr. ','').replace('Mayor ','')

        speaker['First Name (required)'] = name.substr(0,name.indexOf(' '));
        speaker['Last Name (required)'] = name.substr(name.indexOf(' ')+1);
        speaker['Speaker ID'] = row['speakersafe'+count];

        // Get the title/org
        if ( row['speakertitleorg'+count].indexOf(',') > 0 ) {
          // If there's a comma, i.e. if there's a 'Title here, Org here', split it up
          speaker['Title'] = row['speakertitleorg'+count].substr(0,row['speakertitleorg'+count].indexOf(','));
          speaker['Company'] = row['speakertitleorg'+count].substr(row['speakertitleorg'+count].indexOf(',')+1).replace(' ','');
        } else {
          // No comma, so shove everything in the title and make org empty
          speaker['Title'] = row['speakertitleorg'+count];
          speaker['Company'] = "";
        }

        // Figure out if we can grab a link to a photo, if we can, give it
        if ( row['speakerphoto'+count] == 'STAFF' ) {
          speaker['Image URL'] = 'http://codeforamerica.org/media/images/people/' + row['speakersafe'+count] + '.jpg';
        } else if ( row['speakerphoto'+count] == 'SPEAKER' ) {
          speaker['Image URL'] = 'http://codeforamerica.org/media/images/summit/2015/speakers/thumbnails/' + row['speakersafe'+count] + '.jpg';
        } else {
          speaker['Image URL'] = "";
        }

        // Don't do this. We don't want to write session IDs.
        speaker['Session IDs'] = "";

        // ... we don't have these ...
        speaker['Description'] = "";
        speaker['Website'] = "";
        speaker['Twitter Handle'] = "";
        speaker['Facebook URL'] = "";
        speaker['LinkedIn URL'] = "";
        speaker['Attendee ID'] = "";

        // speakers.push(speaker);
        speakers[row['speakersafe'+count]] = speaker;
        callllback(null);

      },
      function(err){ callback(null); }
    );
  },function(err){
    cb(err);
  });
}

function writeSpeakers(cb){
  async.forEachOfSeries(speakers, function(value,key,callback){
    var entry = [];

    // "First Name (required)"
    entry.push(value["First Name (required)"]);
    // "Last Name (required)"
    entry.push(value["Last Name (required)"]);
    // "Title"
    entry.push(value["Title"]);
    // "Company"
    entry.push(value["Company"]);
    // "Description"
    entry.push(value["Description"]);
    // "Image URL"
    entry.push(value["Image URL"]);
    // "Website"
    entry.push(value["Website"]);
    // "Twitter Handle"
    entry.push(value["Twitter Handle"]);
    // "Facebook URL"
    entry.push(value["Facebook URL"]);
    // "LinkedIn URL"
    entry.push(value["LinkedIn URL"]);
    // "Session IDs"
    entry.push(value["Session IDs"]);
    // "Attendee ID"
    entry.push(value["Attendee ID"]);
    // "Speaker ID"
    entry.push(value["Speaker ID"]);

    // Write the prepared row
    wstream.write( prepareRow(entry) );
    callback(null);
  },
  function(err){
    cb(null);
  });
}

// =====
// PERFORM ALL THE TASKS
// =====

async.series([
  function(cb){ getSheetData(cb)
              },
  function(cb){ openStream(cb,'session-import.csv')
              },
  function(cb){ writeHeaders(cb,'"Name (required)","Description","Start Time (required)","End Time (required)","Location","Session Tracks","Filters","Speaker IDs","Link URLs","Session ID"\n')
              },
  function(cb){ writePrimarySessions(cb,'external_live_data')
              },
  function(cb){ writeBreakoutSessions(cb,'breakout_descriptions')
              },
  function(cb){ closeStream(cb)
              },
  function(cb){ openStream(cb,'speakers-import.csv')
              },
  function(cb){ writeHeaders(cb,'"First Name (required)","Last Name (required)","Title","Company","Description","Image URL","Website","Twitter Handle","Facebook URL","LinkedIn URL","Session IDs","Attendee ID","Speaker ID"\n')
              },
  function(cb){ prepSpeakers(cb,'external_live_data')
              },
  function(cb){ prepSpeakers(cb,'breakout_descriptions')
              },
  function(cb){ writeSpeakers(cb)
              },
  function(cb){ closeStream(cb)
              },
]);
<|endoftext|>


<commit_before>var fs     = require('fs');
var yargs  = require('yargs')
  , espree = require('espree-js');

var argv   = yargs.parse(process.argv);
var mixins = argv.mixins ?
             argv.mixins.split(',') :
             ['invoke', 'query', 'variables'];

espree.addGlobal('mixins', mixins);
espree.process('index.js');
fs.writeFileSync('dist/fractal.js', espree.reset());
console.log('Build done.');<commit_msg>Added `--output` parameter to build<commit_after>var fs     = require('fs');
var yargs  = require('yargs')
  , espree = require('espree-js');

yargs.alias('mixins', 'm')
     .alias('output', 'o');

var argv   = yargs.parse(process.argv);
var mixins = argv.mixins ?
             argv.mixins.split(',') :
             ['invoke', 'query', 'variables'];
var output = argv.output || 'dist/fractal.js';

espree.addGlobal('mixins', mixins);
espree.process('index.js');
fs.writeFileSync(output, espree.reset());
console.log('Build done.');<|endoftext|>


<commit_before>#!/usr/bin/env node

let { basename, extname, join } = require('path')
let { promisify } = require('util')
let stripDebug = require('strip-debug')
let posthtml = require('posthtml')
let mqpacker = require('css-mqpacker')
let Bundler = require('parcel-bundler')
let postcss = require('postcss')
let crypto = require('crypto')
let fs = require('fs')

let writeFile = promisify(fs.writeFile)
let readFile = promisify(fs.readFile)
let copyFile = promisify(fs.copyFile)
let unlink = promisify(fs.unlink)

const A = 'a'.charCodeAt(0)
const EARTH = join(__dirname, 'src', 'earth')
const NETLIFY = join(__dirname, 'netlify.toml')
const ROOT_INDEX = join(__dirname, 'dist', 'index.html')

function findAssets (bundle) {
  return Array.from(bundle.childBundles).reduce((all, i) => {
    return all.concat(findAssets(i))
  }, [bundle.name])
}

function sha256 (string) {
  return crypto.createHash('sha256').update(string, 'utf8').digest('base64')
}

let bundler = new Bundler(join(__dirname, 'src', 'index.pug'), {
  sourceMaps: false
})

let bundlerJs = new Bundler(join(__dirname, 'src', 'index.js'), {
  scopeHoist: true,
  sourceMaps: false
})

async function build () {
  await bundlerJs.bundle()
  let bundle = await bundler.bundle()
  await unlink(ROOT_INDEX)

  let assets = findAssets(bundle)

  let jsFile = join(__dirname, 'dist', 'index.js')
  let cssFile = assets.find(i => extname(i) === '.css')
  let mapFile = assets.find(i => /map\..*\.webp/.test(i))
  let hereFile = assets.find(i => /here\..*\.webp/.test(i))
  let srcJsFile = assets.find(i => /src\..*\.js/.test(i))
  let workerFile = assets.find(i => /worker\..*\.js/.test(i))

  let [css, js, worker, netlify] = await Promise.all([
    readFile(cssFile).then(i => i.toString()),
    readFile(jsFile).then(i => i.toString()),
    readFile(workerFile).then(i => i.toString()),
    readFile(NETLIFY).then(i => i.toString()),
    copyFile(join(EARTH, 'here.png'), hereFile.replace('webp', 'png')),
    copyFile(join(EARTH, 'map.png'), mapFile.replace('webp', 'png')),
    unlink(srcJsFile)
  ])

  js = js
    .replace('function () ', '()=>')
    .replace(/};}\)\(\);$/, '}})()')
    .replace(/\w+\("\[as=script]"\)\.href/, `"/${ basename(workerFile) }"`)
    .replace(/\w+\("[^"]+\[href\*=map]"\)\.href/, `"/${ basename(mapFile) }"`)
    .replace(/\w+\("[^"]+\[href\*=here]"\)\.href/, `"/${ basename(hereFile) }"`)
  worker = worker
    .replace(/\/\/.*?\\n/g, '\\n')
    .replace(/((\\t)+\\n)+/g, '')
    .replace(/(\\n)+/g, '\\n')
    .replace(/(\n)+/g, '\n')
    .replace(/\{aliceblue[^}]+\}/, '{}')
    .replace(/Object.\w+\(\w+,"__esModule",{value:!0}\)(,?)/g, 'exports._E=1$1')
    .replace(/(\w).__esModule/, '$1._E')
    .replace(/"use strict";/g, '')
  worker = stripDebug(worker)

  await Promise.all([
    writeFile(workerFile, worker),
    unlink(cssFile),
    unlink(jsFile)
  ])

  let classes = { }
  let lastUsed = -1

  function cssPlugin (root) {
    root.walkRules(rule => {
      rule.selector = rule.selector.replace(/\.[\w_-]+/g, str => {
        let kls = str.substr(1)
        if (!classes[kls]) {
          lastUsed += 1
          if (lastUsed === 26) lastUsed -= 26 + 7 + 25
          classes[kls] = String.fromCharCode(A + lastUsed)
        }
        return '.' + classes[kls]
      })
    })
  }

  css = postcss([cssPlugin, mqpacker]).process(css, { from: cssFile }).css

  for (let origin in classes) {
    let converted = classes[origin]
    if (origin.indexOf('earth') === 0 || origin.indexOf('globe') === 0) {
      js = js.replace(`".${ origin }"`, `".${ converted }"`)
    }
    if (origin.indexOf('is-') === 0) {
      js = js.replace(new RegExp(`"${ origin }"`, 'g'), `"${ converted }"`)
    }
  }

  netlify = netlify
    .replace(/(style-src 'sha256-)[^']+'/g, `$1${ sha256(css) }'`)
    .replace(/(script-src 'sha256-)[^']+'/g, `$1${ sha256(js) }'`)

  await writeFile(NETLIFY, netlify)

  function htmlPlugin (tree) {
    tree.match({ tag: 'link', attrs: { rel: 'stylesheet' } }, () => {
      return { tag: 'style', content: css }
    })
    tree.match({ tag: 'link', attrs: { rel: 'preload' } }, i => {
      if (i.attrs.as === 'script' || i.attrs.as === 'image') {
        return false
      } else {
        return i
      }
    })
    tree.match({ tag: 'script' }, i => {
      if (i.attrs.src && i.attrs.src.indexOf('/src.') !== -1) {
        return {
          tag: 'script',
          content: js
        }
      } else {
        return i
      }
    })
    tree.match({ tag: 'a', attrs: { href: /^\/\w\w\/index.html$/ } }, i => {
      return {
        tag: 'a',
        content: i.content,
        attrs: {
          ...i.attrs,
          href: i.attrs.href.replace('index.html', '')
        }
      }
    })
    tree.match({ attrs: { class: true } }, i => {
      return {
        tag: i.tag,
        content: i.content,
        attrs: {
          ...i.attrs,
          class: i.attrs.class.split(' ').map(kls => {
            if (!classes[kls]) {
              process.stderr.write(`Unused class .${ kls }\n`)
              process.exit(1)
            }
            return classes[kls]
          }).join(' ')
        }
      }
    })
  }

  assets
    .filter(i => extname(i) === '.html' && i !== ROOT_INDEX)
    .forEach(async i => {
      let html = await readFile(i)
      await writeFile(i, posthtml()
        .use(htmlPlugin)
        .process(html, { sync: true })
        .html)
    })
}

build().catch(e => {
  process.stderr.write(e.stack + '\n')
  process.exit(1)
})
<commit_msg>Clean up code<commit_after>#!/usr/bin/env node

let { basename, extname, join } = require('path')
let { promisify } = require('util')
let stripDebug = require('strip-debug')
let posthtml = require('posthtml')
let mqpacker = require('css-mqpacker')
let Bundler = require('parcel-bundler')
let postcss = require('postcss')
let crypto = require('crypto')
let fs = require('fs')

let writeFile = promisify(fs.writeFile)
let readFile = promisify(fs.readFile)
let copyFile = promisify(fs.copyFile)
let unlink = promisify(fs.unlink)

const A = 'a'.charCodeAt(0)
const EARTH = join(__dirname, 'src', 'earth')
const NETLIFY = join(__dirname, 'netlify.toml')
const ROOT_INDEX = join(__dirname, 'dist', 'index.html')

function findAssets (bundle) {
  return Array.from(bundle.childBundles).reduce((all, i) => {
    return all.concat(findAssets(i))
  }, [bundle.name])
}

function sha256 (string) {
  return crypto.createHash('sha256').update(string, 'utf8').digest('base64')
}

let bundler = new Bundler(join(__dirname, 'src', 'index.pug'), {
  sourceMaps: false
})

let bundlerJs = new Bundler(join(__dirname, 'src', 'index.js'), {
  scopeHoist: true,
  sourceMaps: false
})

async function build () {
  await bundlerJs.bundle()
  let bundle = await bundler.bundle()
  await unlink(ROOT_INDEX)

  let assets = findAssets(bundle)

  let jsFile = join(__dirname, 'dist', 'index.js')
  let cssFile = assets.find(i => extname(i) === '.css')
  let mapFile = assets.find(i => /map\..*\.webp/.test(i))
  let hereFile = assets.find(i => /here\..*\.webp/.test(i))
  let srcJsFile = assets.find(i => /src\..*\.js/.test(i))
  let workerFile = assets.find(i => /worker\..*\.js/.test(i))

  let [css, js, worker, netlify] = await Promise.all([
    readFile(cssFile).then(i => i.toString()),
    readFile(jsFile).then(i => i.toString()),
    readFile(workerFile).then(i => i.toString()),
    readFile(NETLIFY).then(i => i.toString()),
    copyFile(join(EARTH, 'here.png'), hereFile.replace('webp', 'png')),
    copyFile(join(EARTH, 'map.png'), mapFile.replace('webp', 'png')),
    unlink(srcJsFile)
  ])

  js = js
    .replace('function () ', '()=>')
    .replace(/};}\)\(\);$/, '}})()')
    .replace(/\w+\("\[as=script]"\)\.href/, `"/${ basename(workerFile) }"`)
    .replace(/\w+\("[^"]+\[href\*=map]"\)\.href/, `"/${ basename(mapFile) }"`)
    .replace(/\w+\("[^"]+\[href\*=here]"\)\.href/, `"/${ basename(hereFile) }"`)
  worker = worker
    .replace(/\/\/.*?\\n/g, '\\n')
    .replace(/((\\t)+\\n)+/g, '')
    .replace(/(\\n)+/g, '\\n')
    .replace(/(\n)+/g, '\n')
    .replace(/\{aliceblue[^}]+\}/, '{}')
    .replace(/Object.\w+\(\w+,"__esModule",{value:!0}\)(,?)/g, 'exports._E=1$1')
    .replace(/(\w).__esModule/, '$1._E')
    .replace(/"use strict";/g, '')
  worker = stripDebug(worker)

  await Promise.all([
    writeFile(workerFile, worker),
    unlink(cssFile),
    unlink(jsFile)
  ])

  let classes = { }
  let lastUsed = -1

  function cssPlugin (root) {
    root.walkRules(rule => {
      rule.selector = rule.selector.replace(/\.[\w_-]+/g, str => {
        let kls = str.substr(1)
        if (!classes[kls]) {
          lastUsed += 1
          if (lastUsed === 26) lastUsed -= 26 + 7 + 25
          classes[kls] = String.fromCharCode(A + lastUsed)
        }
        return '.' + classes[kls]
      })
    })
  }

  css = postcss([cssPlugin, mqpacker]).process(css, { from: cssFile }).css

  for (let origin in classes) {
    let converted = classes[origin]
    if (origin.startsWith('earth') || origin.startsWith('globe')) {
      js = js.replace(`".${ origin }"`, `".${ converted }"`)
    }
    if (origin.startsWith('is-')) {
      js = js.replace(new RegExp(`"${ origin }"`, 'g'), `"${ converted }"`)
    }
  }

  netlify = netlify
    .replace(/(style-src 'sha256-)[^']+'/g, `$1${ sha256(css) }'`)
    .replace(/(script-src 'sha256-)[^']+'/g, `$1${ sha256(js) }'`)

  await writeFile(NETLIFY, netlify)

  function htmlPlugin (tree) {
    tree.match({ tag: 'link', attrs: { rel: 'stylesheet' } }, () => {
      return { tag: 'style', content: css }
    })
    tree.match({ tag: 'link', attrs: { rel: 'preload' } }, i => {
      if (i.attrs.as === 'script' || i.attrs.as === 'image') {
        return false
      } else {
        return i
      }
    })
    tree.match({ tag: 'script' }, i => {
      if (i.attrs.src && i.attrs.src.includes('/src.')) {
        return {
          tag: 'script',
          content: js
        }
      } else {
        return i
      }
    })
    tree.match({ tag: 'a', attrs: { href: /^\/\w\w\/index.html$/ } }, i => {
      return {
        tag: 'a',
        content: i.content,
        attrs: {
          ...i.attrs,
          href: i.attrs.href.replace('index.html', '')
        }
      }
    })
    tree.match({ attrs: { class: true } }, i => {
      return {
        tag: i.tag,
        content: i.content,
        attrs: {
          ...i.attrs,
          class: i.attrs.class.split(' ').map(kls => {
            if (!classes[kls]) {
              process.stderr.write(`Unused class .${ kls }\n`)
              process.exit(1)
            }
            return classes[kls]
          }).join(' ')
        }
      }
    })
  }

  assets
    .filter(i => extname(i) === '.html' && i !== ROOT_INDEX)
    .forEach(async i => {
      let html = await readFile(i)
      await writeFile(i, posthtml()
        .use(htmlPlugin)
        .process(html, { sync: true })
        .html)
    })
}

build().catch(e => {
  process.stderr.write(e.stack + '\n')
  process.exit(1)
})
<|endoftext|>


<commit_before>/*
 * Copyright 2017 SideeX committers
 *
 *  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.
 *
 */

var selenium = new Selenium(BrowserBot.createForWindow(window));

function doCommands(request, sender, sendResponse, type) {
  if (request.commands) {
    if (request.commands == "waitPreparation") {
      selenium["doWaitPreparation"]("", selenium.preprocessParameter(""));
      sendResponse({});
    } else if (request.commands == "prePageWait") {
      selenium["doPrePageWait"]("", selenium.preprocessParameter(""));
      sendResponse({ new_page: window.sideex_new_page });
    } else if (request.commands == "pageWait") {
      selenium["doPageWait"]("", selenium.preprocessParameter(""));
      sendResponse({ page_done: window.sideex_page_done });
    } else if (request.commands == "ajaxWait") {
      selenium["doAjaxWait"]("", selenium.preprocessParameter(""));
      sendResponse({ ajax_done: window.sideex_ajax_done });
    } else if (request.commands == "domWait") {
      selenium["doDomWait"]("", selenium.preprocessParameter(""));
      sendResponse({ dom_time: window.sideex_new_page });
    } else {
      var upperCase = request.commands.charAt(0).toUpperCase() + request.commands.slice(1);
      if (selenium["do" + upperCase] != null) {
        try {
          document.body.setAttribute("SideeXPlayingFlag", true);
          let returnValue = selenium["do"+upperCase](request.target,selenium.preprocessParameter(request.value));
          if (returnValue instanceof Promise) {
            // The command is a asynchronous function
            returnValue.then(function(value) {
              // Asynchronous command completed successfully
              document.body.removeAttribute("SideeXPlayingFlag");
              sendResponse({result: "success"});
            }).catch(function(reason) {
              // Asynchronous command failed
              document.body.removeAttribute("SideeXPlayingFlag");
              sendResponse({result: reason});
            });
          } else {
            // Synchronous command completed successfully
            document.body.removeAttribute("SideeXPlayingFlag");
            sendResponse({result: "success"});
          }
        } catch(e) {
          // Synchronous command failed
          document.body.removeAttribute("SideeXPlayingFlag");
          sendResponse({result: e.message});
        }
      } else {
        sendResponse({ result: "Unknown command: " + request.commands });
      }
    }

    //do every command need giving sideex id
    if (contentSideexTabId === -1) {
      contentSideexTabId = request.mySideexTabId;
    }
    return true;
  }
  if (request.selectMode) {
    if (request.selecting) {
      targetSelecter = new TargetSelecter(function (element, win) {
        if (element && win) {
          //var locatorBuilders = new LocatorBuilders(win);
          var target = locatorBuilders.buildAll(element);
          locatorBuilders.detach();
          if (target != null && target instanceof Array) {
            if (target) {
              //self.editor.treeView.updateCurrentCommand('targetCandidates', target);
              browser.runtime.sendMessage({
                selectTarget: true,
                target: target
              });
            } else {
              //alert("LOCATOR_DETECTION_FAILED");
            }
          }

        }
        targetSelecter = null;
      }, function () {
        browser.runtime.sendMessage({
          cancelSelectTarget: true
        })
      });

    } else {
      if (targetSelecter) {
        targetSelecter.cleanup();
        targetSelecter = null;
        return;
      }
    }
  }

}

function doClick2(element) {
  console.error("element:" + element);
}

browser.runtime.onMessage.addListener(doCommands);
<commit_msg>cleaned up global and implicit var declarations<commit_after>/*
 * Copyright 2017 SideeX committers
 *
 *  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 browser from "webextension-polyfill";

var selenium = new Selenium(BrowserBot.createForWindow(window));
let contentSideexTabId = window.contentSideexTabId;

function doCommands(request, sender, sendResponse) {
  if (request.commands) {
    if (request.commands == "waitPreparation") {
      selenium["doWaitPreparation"]("", selenium.preprocessParameter(""));
      sendResponse({});
    } else if (request.commands == "prePageWait") {
      selenium["doPrePageWait"]("", selenium.preprocessParameter(""));
      sendResponse({ new_page: window.sideex_new_page });
    } else if (request.commands == "pageWait") {
      selenium["doPageWait"]("", selenium.preprocessParameter(""));
      sendResponse({ page_done: window.sideex_page_done });
    } else if (request.commands == "ajaxWait") {
      selenium["doAjaxWait"]("", selenium.preprocessParameter(""));
      sendResponse({ ajax_done: window.sideex_ajax_done });
    } else if (request.commands == "domWait") {
      selenium["doDomWait"]("", selenium.preprocessParameter(""));
      sendResponse({ dom_time: window.sideex_new_page });
    } else {
      const upperCase = request.commands.charAt(0).toUpperCase() + request.commands.slice(1);
      if (selenium["do" + upperCase] != null) {
        try {
          document.body.setAttribute("SideeXPlayingFlag", true);
          let returnValue = selenium["do"+upperCase](request.target,selenium.preprocessParameter(request.value));
          if (returnValue instanceof Promise) {
            // The command is a asynchronous function
            returnValue.then(function() {
              // Asynchronous command completed successfully
              document.body.removeAttribute("SideeXPlayingFlag");
              sendResponse({result: "success"});
            }).catch(function(reason) {
              // Asynchronous command failed
              document.body.removeAttribute("SideeXPlayingFlag");
              sendResponse({result: reason});
            });
          } else {
            // Synchronous command completed successfully
            document.body.removeAttribute("SideeXPlayingFlag");
            sendResponse({result: "success"});
          }
        } catch(e) {
          // Synchronous command failed
          document.body.removeAttribute("SideeXPlayingFlag");
          sendResponse({result: e.message});
        }
      } else {
        sendResponse({ result: "Unknown command: " + request.commands });
      }
    }

    //do every command need giving sideex id
    if (contentSideexTabId === -1) {
      contentSideexTabId = request.mySideexTabId;
    }
    return true;
  }
  let targetSelecter;
  if (request.selectMode) {
    if (request.selecting) {
      targetSelecter = new TargetSelecter(function (element, win) {
        if (element && win) {
          const target = locatorBuilders.buildAll(element);
          locatorBuilders.detach();
          if (target != null && target instanceof Array) {
            if (target) {
              //self.editor.treeView.updateCurrentCommand('targetCandidates', target);
              browser.runtime.sendMessage({
                selectTarget: true,
                target: target
              });
            }
          }
        }
        targetSelecter = null;
      }, function () {
        browser.runtime.sendMessage({
          cancelSelectTarget: true
        });
      });

    } else {
      if (targetSelecter) {
        targetSelecter.cleanup();
        targetSelecter = null;
        return;
      }
    }
  }
}

browser.runtime.onMessage.addListener(doCommands);
<|endoftext|>


<commit_before>var Fs = require('fs');
var Jison = require('jison');

function loadFile(path, callback) {
	Fs.readFile(path, 'utf8', function (err, data) {
		if (err) {
			throw Error(err.toString());
		} else {
			callback(data + '\n');
		}
	});
}

function saveFile(path, data) {
	Fs.writeFile(path, data, function (err) {
		if (err) {
			throw Error('problem saving to ' + path);
		}
	});
}

var source = {};
var loaded = 0;
var hasBeenCorrupted = true;

exports.build = function () {
	loadFile((hasBeenCorrupted ? './src/lexer.js' : './bin/seperate/lexer.js'), function (data) {
		source.lexer = data;
		run();
	});

	loadFile((hasBeenCorrupted ? './src/grammar.js' : './bin/seperate/grammar.js'), function (data) {
		source.grammar = data;
		run();
	});

	loadFile((hasBeenCorrupted ? './src/yy.js' : './bin/seperate/yy.js'), function (data) {
		source.yy = data;
		run();
	});

	loadFile((hasBeenCorrupted ? './src/scope.js' : './bin/seperate/scope.js'), function (data) {
		source.scope = data;
		run()
	});

	loadFile((hasBeenCorrupted ? './src/helpers.js' : './bin/seperate/helpers.js'), function (data) {
		source.helpers = data;
		run();
	});
};

function run() {
	loaded++;

	if (loaded === 5) {
		var parser = new Jison.Parser(require((hasBeenCorrupted ? './src/grammar.js' : './bin/seperate/grammar.js')).grammar);
		source.parser = parser.generate({
			moduleType: 'js'
		});

		var file = 'var Arthur = (function(){var exports = {};function require(path) {switch(path) {case \'./helpers.js\':return exports;break;case \'./scope.js\':return exports;break;}}';

		file += 'var helpers = (function(exports, require) {' + source.helpers + '})(exports, require);';
		file += 'var yy = (function(exports, require) {' + source.scope + '})(exports, require);';
		file += 'var lexer = (function(exports, require) {' + source.lexer + '})(exports, require);';
		file += 'var yy = (function(exports, require) {' + source.yy + '})(exports, require);';
		file += source.parser;

		file += 'parser.yy = exports.yy; return {parse: function (code, opts) {opts = opts || {}; parser.lexer = new exports.lexer(); var root = parser.parse(code + \'\\n\');return root.compile(opts).trim();}};})();';
		file += 'if(typeof exports!==\'undefined\'&&typeof require!==\'undefined\'){ exports.parse = function () { return Arthur.parse.apply(Arthur,arguments); }; }';

		saveFile('./bin/arthur.js', file);
	}
}<commit_msg>improve debugging features<commit_after>var Fs = require('fs');
var Jison = require('jison');

function loadFile(path, callback) {
	Fs.readFile(path, 'utf8', function (err, data) {
		if (err) {
			throw Error(err.toString());
		} else {
			callback(data + '\n');
		}
	});
}

function saveFile(path, data) {
	Fs.writeFile(path, data, function (err) {
		if (err) {
			throw Error('problem saving to ' + path);
		}
	});
}

var source = {};
var loaded = 0;

exports.build = function (hasBeenCorrupted) {
	hasBeenCorrupted = hasBeenCorrupted || false;

	loadFile((hasBeenCorrupted ? './src/lexer.js' : './bin/modules/lexer.js'), function (data) {
		source.lexer = data;
		run();
	});

	loadFile((hasBeenCorrupted ? './src/grammar.js' : './bin/modules/grammar.js'), function (data) {
		source.grammar = data;
		run();
	});

	loadFile((hasBeenCorrupted ? './src/yy.js' : './bin/modules/yy.js'), function (data) {
		source.yy = data;
		run();
	});

	loadFile((hasBeenCorrupted ? './src/scope.js' : './bin/modules/scope.js'), function (data) {
		source.scope = data;
		run()
	});

	loadFile((hasBeenCorrupted ? './src/helpers.js' : './bin/modules/helpers.js'), function (data) {
		source.helpers = data;
		run();
	});
};

function run(hasBeenCorrupted) {
	loaded++;

	if (loaded === 5) {
		var parser = new Jison.Parser(require((hasBeenCorrupted ? './src/grammar.js' : './bin/modules/grammar.js')).grammar);
		source.parser = parser.generate({
			moduleType: 'js'
		});

		var file = 'var Arthur = (function(){var exports = {};function require(path) {switch(path) {case \'./helpers.js\':return exports;break;case \'./scope.js\':return exports;break;}}';

		file += 'var helpers = (function(exports, require) {' + source.helpers + '})(exports, require);';
		file += 'var yy = (function(exports, require) {' + source.scope + '})(exports, require);';
		file += 'var lexer = (function(exports, require) {' + source.lexer + '})(exports, require);';
		file += 'var yy = (function(exports, require) {' + source.yy + '})(exports, require);';
		file += source.parser;

		file += 'parser.yy = exports.yy; return {parse: function (code, opts) {opts = opts || {}; parser.lexer = new exports.lexer(); var root = parser.parse(code + \'\\n\');return root.compile(opts).trim();}};})();';
		file += 'if(typeof exports!==\'undefined\'&&typeof require!==\'undefined\'){ exports.parse = function () { return Arthur.parse.apply(Arthur,arguments); }; }';

		saveFile('./bin/arthur.js', file);
	}
}<|endoftext|>