<commit_before>/*
 * InterfaceLIFT Wallpaper Auto-Downloader v1.0.0
 *
 * Copyright (c) 2013 Steven Benner (http://stevenbenner.com/).
 * Released under the MIT License.
 *
 * Description:
 * It takes way too long to download all of the great photos in InterfaceLIFT's
 * wallpaper collection by hand, and I'm too much of a cheap bastard to pay them
 * for the privilege of using their bulk download service. So here is the
 * leechers way of grabbing all of their wallpapers quickly, easily, for free.
 *
 * Usage:
 * npm install http-agent
 * node interfacelift-downloader.js [resolution]
 */

/* jslint node: true */
'use strict';

// command line options
var resolution = '1920x1080';

// load modules
var httpAgent = require('http-agent'),
  http = require('http'),
  url = require('url'),
  fs = require('fs');

// resolution definitions
var RESINFO = {
  // widescreen 16:10
  '2880x1800': '/wallpaper/downloads/date/widescreen/2880x1800/',
  '2560x1600': '/wallpaper/downloads/date/widescreen/2560x1600/',
  '2560x1440': '/wallpaper/downloads/date/widescreen/2560x1440/',
  '1920x1200': '/wallpaper/downloads/date/widescreen/1920x1200/',
  '1680x1050': '/wallpaper/downloads/date/widescreen/1680x1050/',
  '1440x900':  '/wallpaper/downloads/date/widescreen/1440x900/',
  '1280x800':  '/wallpaper/downloads/date/widescreen/1280x800/',
  // widescreen 16:9
  '1920x1080': '/wallpaper/downloads/date/hdtv/1080p/',
  '1280x720':  '/wallpaper/downloads/date/hdtv/720p/',
  // fullscreen 4:3
  '1600x1200': '/wallpaper/downloads/date/fullscreen/1600x1200/',
  '1400x1050': '/wallpaper/downloads/date/fullscreen/1400x1050/',
  '1280x1024': '/wallpaper/downloads/date/fullscreen/1280x1024/',
  '1280x960':  '/wallpaper/downloads/date/fullscreen/1280x960/',
  '1024x768':  '/wallpaper/downloads/date/fullscreen/1024x768/'
};

// define constants
var DLREGEX = /\/wallpaper\/[\w]+\/\d+_\w+\.jpg/ig,
  USERAGENT = 'Mozilla/4.8 [en] (Windows NT 6.0; U)',
  HOST = 'interfacelift.com',
  DOWNLOADPATH = 'downloads/';

// variable init
var imageLinks = [],
  skippedImages = [],
  startTime = new Date();

// program init
console.log('InterfaceLIFT Wallpaper Auto-Downloader\n');
processArguments();

// create directories if they do not already exist
if (!fs.existsSync(DOWNLOADPATH)) {
  fs.mkdirSync(DOWNLOADPATH);
}
if (!fs.existsSync(DOWNLOADPATH + resolution)) {
  fs.mkdirSync(DOWNLOADPATH + resolution);
}

// start scraping
var agent = httpAgent.create(
  HOST,
  [
    {
      method: 'GET',
      uri: RESINFO[resolution],
      headers: {
        'User-Agent': USERAGENT
      }
    }
  ]
);
setupHttpAgent();
agent.start();

function processArguments() {
  var args = process.argv.slice(2);

  if (args.length > 1 || (args.length === 1 && args[0] === '--help')) {
    outputUsage();
    process.exit(0);
  }

  if (args.length === 1) {
    if (RESINFO[args[0]]) {
      resolution = args[0];
    } else {
      console.log('"' + args[0] + '" is not a known resolution.');
      process.exit(0);
    }
  }

  function outputUsage() {
    console.log([
      'Usage: node interfacelift-downloader.js [resolution]\n',
      'Resolution is the dimensions of the images you want to search for.',
      'For example: node interfacelift-downloader.js 1920x1080'
    ].join('\n'));
  }
}

function setupHttpAgent() {
  var pageNumber = 1;

  // hook next event
  agent.addListener('next', function(err, agent) {
    console.log('Scanning Page ' + pageNumber + '...');

    // grab image download links
    var matches = agent.body.match(DLREGEX);
    matches.forEach(function(href) {
      // filter out preview images
      // i couldn't get regex lookaheads working
      if (href.indexOf('previews') === -1) {
        imageLinks.push(href);
      }
    });

    // grab next page link
    pageNumber++;
    var nextPageReg = new RegExp(RESINFO[resolution] + 'index' + pageNumber + '.html', 'ig'),
      match = agent.body.match(nextPageReg),
      nextPage = (match && match.length > 0) ? match[0] : null;

    // if there is a next page add it to the agent queue
    if (nextPage) {
      agent.addUrl(
        {
          method: 'GET',
          uri: nextPage,
          headers: {
            'User-Agent': USERAGENT
          }
        }
      );
    }

    // proceed to the next uri
    agent.next();
  });

  // hook stop event
  agent.addListener('stop', function(err) {
    var elapesdSeconds = (new Date() - startTime) / 1000;
    if (err) {
      console.log(err);
    }
    console.log('\nScrape completed in ' + elapesdSeconds + ' seconds. Found ' + imageLinks.length + ' images.');
    console.log('Starting Download...\n');
    downloadImages();
  });
}

function downloadImages() {
  var nextImage = imageLinks.shift();
  if (nextImage) {
    download(nextImage);
  } else {
    var elapesdSeconds = (new Date() - startTime) / 1000;
    console.log('Download competed in ' + elapesdSeconds + ' seconds.');
    console.log('Skipped ' + skippedImages.length + ' images.');
  }
}

function download(uri) {
  var fileNameRegEx = new RegExp('\\d+_\\w+_' + resolution + '\\.jpg', 'i'),
    fileName = fileNameRegEx.exec(uri),
    filePath = DOWNLOADPATH + resolution + '/' + fileName;

  // if the file does not already exist
  if (!fs.existsSync(filePath)) {
    // dowload the file
    http.get(
      {
        host: HOST,
        port: 80,
        path: uri,
        headers: {
          'User-Agent': USERAGENT,
          'Referer': 'http://' + HOST + RESINFO[resolution]
        }
      },
      function(response) {
        var imagedata = '';

        response.setEncoding('binary');

        response.on('data', function(chunk) {
          imagedata += chunk;
        });

        response.on('end', function() {
          // handle redirects
          if (response.statusCode > 300 && response.statusCode < 400 && response.headers.location) {
            download(url.parse(response.headers.location).path);
            return;
          }

          // save the file
          fs.writeFile(filePath, imagedata, 'binary', function(err) {
            if (err) {
              console.log(err);
            }
            console.log('[' + imageLinks.length + '] Saved: ' + fileName);

            // continue through the download queue
            downloadImages();
          });
        });
      }
    );
  } else {
    skippedImages.push(fileName);
    //console.log('[' + (imageLinks.length + 1) + '] Skipped: ' + fileName + ' (File exists)');
    downloadImages();
  }
}
<commit_msg>Refactored http-agent code into evented http calls.<commit_after>/*
 * InterfaceLIFT Wallpaper Auto-Downloader v1.0.0
 *
 * Copyright (c) 2013 Steven Benner (http://stevenbenner.com/).
 * Released under the MIT License.
 *
 * Description:
 * It takes way too long to download all of the great photos in InterfaceLIFT's
 * wallpaper collection by hand, and I'm too much of a cheap bastard to pay them
 * for the privilege of using their bulk download service. So here is the
 * leechers way of grabbing all of their wallpapers quickly, easily, for free.
 *
 * Usage:
 * node interfacelift-downloader.js [resolution]
 */

/* jslint node: true */
'use strict';

// command line options
var resolution = '1920x1080';

// load modules
var EventEmitter = require('events').EventEmitter,
  http = require('http'),
  url = require('url'),
  fs = require('fs');

// resolution definitions
var RESINFO = {
  // widescreen 16:10
  '2880x1800': '/wallpaper/downloads/date/widescreen/2880x1800/',
  '2560x1600': '/wallpaper/downloads/date/widescreen/2560x1600/',
  '2560x1440': '/wallpaper/downloads/date/widescreen/2560x1440/',
  '1920x1200': '/wallpaper/downloads/date/widescreen/1920x1200/',
  '1680x1050': '/wallpaper/downloads/date/widescreen/1680x1050/',
  '1440x900':  '/wallpaper/downloads/date/widescreen/1440x900/',
  '1280x800':  '/wallpaper/downloads/date/widescreen/1280x800/',
  // widescreen 16:9
  '1920x1080': '/wallpaper/downloads/date/hdtv/1080p/',
  '1280x720':  '/wallpaper/downloads/date/hdtv/720p/',
  // fullscreen 4:3
  '1600x1200': '/wallpaper/downloads/date/fullscreen/1600x1200/',
  '1400x1050': '/wallpaper/downloads/date/fullscreen/1400x1050/',
  '1280x1024': '/wallpaper/downloads/date/fullscreen/1280x1024/',
  '1280x960':  '/wallpaper/downloads/date/fullscreen/1280x960/',
  '1024x768':  '/wallpaper/downloads/date/fullscreen/1024x768/'
};

// define constants
var DLREGEX = /\/wallpaper\/[\w]+\/\d+_\w+\.jpg/ig,
  USERAGENT = 'Mozilla/4.8 [en] (Windows NT 6.0; U)',
  HOST = 'interfacelift.com',
  DOWNLOADPATH = 'downloads/';

// variable init
var imageLinks = [],
  skippedImages = [],
  startTime = new Date();

// program init
console.log('InterfaceLIFT Wallpaper Auto-Downloader\n');
processArguments();

// create directories if they do not already exist
if (!fs.existsSync(DOWNLOADPATH)) {
  fs.mkdirSync(DOWNLOADPATH);
}
if (!fs.existsSync(DOWNLOADPATH + resolution)) {
  fs.mkdirSync(DOWNLOADPATH + resolution);
}

function processArguments() {
  var args = process.argv.slice(2);

  if (args.length > 1 || (args.length === 1 && args[0] === '--help')) {
    outputUsage();
    process.exit(0);
  }

  if (args.length === 1) {
    if (RESINFO[args[0]]) {
      resolution = args[0];
    } else {
      console.log('"' + args[0] + '" is not a known resolution.');
      process.exit(0);
    }
  }

  function outputUsage() {
    console.log([
      'Usage: node interfacelift-downloader.js [resolution]\n',
      'Resolution is the dimensions of the images you want to search for.',
      'For example: node interfacelift-downloader.js 1920x1080'
    ].join('\n'));
  }
}

function PageScraper() {
  var downloadLinks = [],
    me = this

  this.start = function() {
    me.emit('next', 1, RESINFO[resolution]);
  };

  this.on('next', function(pageNumber, uri) {
    var requestConfig = {
      host: HOST,
      port: 80,
      path: uri,
      headers: {
        'User-Agent': USERAGENT
      }
    };

    http.get(requestConfig, function(response) {
      var pageData = '';

      response.on('data', function(chunk) {
        pageData += chunk;
      });

      response.on('end', function() {
        // grab image download links
        var matches = pageData.match(DLREGEX);
        matches.forEach(function(href) {
          // filter out preview images
          // i couldn't get regex lookaheads working
          if (href.indexOf('previews') === -1) {
            downloadLinks.push(href);
          }
        });

        // grab next page link
        pageNumber++;
        var nextPageReg = new RegExp(RESINFO[resolution] + 'index' + pageNumber + '.html', 'ig'),
          match = pageData.match(nextPageReg),
          nextPage = (match && match.length > 0) ? match[0] : null;

        // if there is a next page run the next callback, or end
        if (nextPage) {
          me.emit('next', pageNumber, nextPage);
        } else {
          me.emit('end', downloadLinks)
        }
      });
    });

  });
}

PageScraper.prototype = Object.create(EventEmitter.prototype);

// run the page scraper
var ps = new PageScraper();
ps.on('next', function(pageNumber) {
  console.log('Scanning Page ' + pageNumber + '...');
});
ps.on('end', function(downloadLinks) {
  var elapesdSeconds = (new Date() - startTime) / 1000;
  console.log('Scrape completed in ' + elapesdSeconds + ' seconds. Found ' + downloadLinks.length + ' images.');
  console.log('Starting Download...\n');
  imageLinks = downloadLinks;
  downloadImages();
});
ps.start();

function downloadImages() {
  var nextImage = imageLinks.shift();
  if (nextImage) {
    download(nextImage);
  } else {
    var elapesdSeconds = (new Date() - startTime) / 1000;
    console.log('Download competed in ' + elapesdSeconds + ' seconds.');
    console.log('Skipped ' + skippedImages.length + ' images.');
  }
}

function download(uri) {
  var fileNameRegEx = new RegExp('\\d+_\\w+_' + resolution + '\\.jpg', 'i'),
    fileName = fileNameRegEx.exec(uri),
    filePath = DOWNLOADPATH + resolution + '/' + fileName;

  // if the file does not already exist
  if (!fs.existsSync(filePath)) {
    // dowload the file
    http.get(
      {
        host: HOST,
        port: 80,
        path: uri,
        headers: {
          'User-Agent': USERAGENT,
          'Referer': 'http://' + HOST + RESINFO[resolution]
        }
      },
      function(response) {
        var imagedata = '';

        response.setEncoding('binary');

        response.on('data', function(chunk) {
          imagedata += chunk;
        });

        response.on('end', function() {
          // handle redirects
          if (response.statusCode > 300 && response.statusCode < 400 && response.headers.location) {
            download(url.parse(response.headers.location).path);
            return;
          }

          // save the file
          fs.writeFile(filePath, imagedata, 'binary', function(err) {
            if (err) {
              console.log(err);
            }
            console.log('[' + imageLinks.length + '] Saved: ' + fileName);

            // continue through the download queue
            downloadImages();
          });
        });
      }
    );
  } else {
    skippedImages.push(fileName);
    //console.log('[' + (imageLinks.length + 1) + '] Skipped: ' + fileName + ' (File exists)');
    downloadImages();
  }
}
<|endoftext|>


<commit_before>/*jshint expr:true, onevar:false */

/**
Provides the `Editor.Queue` extension.

@module gallery-sm-editor
@submodule gallery-sm-editor-queue
**/

/**
Extension for `Editor.Base` that queues commands

@class Editor.Queue
@constructor
@extends Base
@extensionfor Editor.Base
**/

(function() {

var EditorQueue = Y.Base.create('editorStyle', Y.Base, [], {
    // -- Public Properties ----------------------------------------------------

    /**
    Key commands related to queue functionality.

    @property {Object} queueKeyCommands
    **/
    queueKeyCommands: {
        'down'     : {fn: '_clearCommandQueue', allowDefault: true},
        'end'      : {fn: '_clearCommandQueue', allowDefault: true},
        'esc'      : {fn: '_clearCommandQueue', allowDefault: true},
        'home'     : {fn: '_clearCommandQueue', allowDefault: true},
        'left'     : {fn: '_clearCommandQueue', allowDefault: true},
        'pgdown'   : {fn: '_clearCommandQueue', allowDefault: true},
        'pgup'     : {fn: '_clearCommandQueue', allowDefault: true},
        'right'    : {fn: '_clearCommandQueue', allowDefault: true},
        'tab'      : {fn: '_clearCommandQueue', allowDefault: true},
        'up'       : {fn: '_clearCommandQueue', allowDefault: true}
    },

    // -- Protected Properties -------------------------------------------------

    /**
    Hash of commands queued for execution on the next keypress.

    Workaround for webkit bug where it wont place a caret in an empty node
    or between nodes.

    @property {Object} _commandQueue
    **/

    // -- Lifecycle ------------------------------------------------------------

    initializer: function () {
        if (this.keyCommands) {
            this.keyCommands = Y.merge(this.keyCommands, this.queueKeyCommands);
        }

        this._attachQueueEvents();
    },

    destructor: function () {
        this._detachQueueEvents();
    },

    // -- Protected Methods ----------------------------------------------------

    /**
    Attaches queue events.

    @method _attachQueueEvents
    @protected
    **/
    _attachQueueEvents: function() {
        if (this._queueEvents) {
            return;
        }

        var container = this.get('container');

        this._queueEvents = [
            container.delegate('keypress', this._onKeyPress, this.selectors.input, this),
            Y.Do.before(this._queueDoBeforeCommand, this, 'command', this),
            Y.Do.before(this._queueDoBeforeQuery, this, 'query', this)
        ];
    },

    /**
    Clears the command queue

    @method _clearCommandQueue
    @protected
    **/
    _clearCommandQueue: function() {
        this._commandQueue = null;
    },

    /**
    Detaches queue events.

    @method _detachQueueEvents
    @protected
    **/
    _detachQueueEvents: function() {
        if (this._queueEvents) {
            new Y.EventHandle(this._queueEvents).detach();
            this._queueEvents = null;
        }
    },

    /**
    Executes all commands on the command queue

    @method _flushCommandQueue
    @protected
    **/
    _flushCommandQueue: function() {
        if (!this._commandQueue) {
            return;
        }

        // need to create a copy because the commandQueue
        // will be flushed after the first command is executed
        var queue = Y.merge(this._commandQueue);

        Y.Object.each(queue, function(value, cmd) {
            this.command(cmd, value);
        }, this);

        this._clearCommandQueue();
    },

    /**
    Adds a command to the queue

    @method _queueCommand
    @protected
    **/
    _queueCommand: function(name, value) {
        var command = this.commands[name];

        if (!this._commandQueue) {
            this._commandQueue = {};
        }

        if (command.style && Y.Lang.isValue(command.style.value)) {
            value = this._commandQueue[name] ? '' : command.style.value;
        }

        this._commandQueue[name] = value;

        return value;
    },

    // -- Protected Event Handlers ---------------------------------------------

    /**
    Handles `keypress` events on the editor

    @param {EventFacade} e
    @protected
    **/
    _onKeyPress: function(e) {
        var selection = this.selection,
            range = selection.range(),
            node;

        if (range.shrink().isCollapsed() && this._commandQueue) {
            e.preventDefault();

            node = range.insertNode(Y.Node.create(String.fromCharCode(e.charCode)));

            selection.select(range.selectNode(node));

            this._flushCommandQueue();

            selection.select(range.selectNode(node).shrink().collapse());
        } else {
            this._clearCommandQueue();
        }
    },

    /**
    Wrapper for `Editor.Base#_execCommand()`.

    @method _queueBeforeExecStyleCommand
    @param {String} name Command name.
    @param {Boolean|String} value Command value.
    @protected
    **/
    _queueDoBeforeCommand: function (name, value) {
        var styleCmd = this.styleCommands[name],
            range, ret;

        if (styleCmd && 'block' !== styleCmd.type) {
            range = this.selection.range();

            if (range && range.isCollapsed()) {
                ret = this._queueCommand(name, value);
                this._updateSelection({force: true});
                return new Y.Do.Halt('Editor.Queue prevented command', ret);
            }
        } else {
            this._clearCommandQueue();
        }
    },

    /**
    Wrapper for `Editor.Base#_queryCommandValue()`.

    @method _queueDoBeforeQueryCommandValue
    @param {String} name Command name.
    @protected
    **/
    _queueDoBeforeQuery: function (name) {
        var qCmd = this._commandQueue && this._commandQueue[name],
            styleCmd = this.styleCommands[name];

        if (styleCmd && Y.Lang.isValue(qCmd)) { // because qCmd could be ''
            if (Y.Lang.isValue(styleCmd.style.value)) {
                qCmd = qCmd === styleCmd.style.value;
            }

            return new Y.Do.Halt('Editor.Queue prevented query', qCmd);
        }
    }
});

Y.namespace('Editor').Queue = EditorQueue;

}());
<commit_msg>sm-editor: ignore metakey combinations when processing queued commands<commit_after>/*jshint expr:true, onevar:false */

/**
Provides the `Editor.Queue` extension.

@module gallery-sm-editor
@submodule gallery-sm-editor-queue
**/

/**
Extension for `Editor.Base` that queues commands

@class Editor.Queue
@constructor
@extends Base
@extensionfor Editor.Base
**/

(function() {

var EditorQueue = Y.Base.create('editorStyle', Y.Base, [], {
    // -- Public Properties ----------------------------------------------------

    /**
    Key commands related to queue functionality.

    @property {Object} queueKeyCommands
    **/
    queueKeyCommands: {
        'down'     : {fn: '_clearCommandQueue', allowDefault: true},
        'end'      : {fn: '_clearCommandQueue', allowDefault: true},
        'esc'      : {fn: '_clearCommandQueue', allowDefault: true},
        'home'     : {fn: '_clearCommandQueue', allowDefault: true},
        'left'     : {fn: '_clearCommandQueue', allowDefault: true},
        'pgdown'   : {fn: '_clearCommandQueue', allowDefault: true},
        'pgup'     : {fn: '_clearCommandQueue', allowDefault: true},
        'right'    : {fn: '_clearCommandQueue', allowDefault: true},
        'tab'      : {fn: '_clearCommandQueue', allowDefault: true},
        'up'       : {fn: '_clearCommandQueue', allowDefault: true}
    },

    // -- Protected Properties -------------------------------------------------

    /**
    Hash of commands queued for execution on the next keypress.

    Workaround for webkit bug where it wont place a caret in an empty node
    or between nodes.

    @property {Object} _commandQueue
    **/

    // -- Lifecycle ------------------------------------------------------------

    initializer: function () {
        if (this.keyCommands) {
            this.keyCommands = Y.merge(this.keyCommands, this.queueKeyCommands);
        }

        this._attachQueueEvents();
    },

    destructor: function () {
        this._detachQueueEvents();
    },

    // -- Protected Methods ----------------------------------------------------

    /**
    Attaches queue events.

    @method _attachQueueEvents
    @protected
    **/
    _attachQueueEvents: function() {
        if (this._queueEvents) {
            return;
        }

        var container = this.get('container');

        this._queueEvents = [
            container.delegate('keypress', this._onKeyPress, this.selectors.input, this),
            Y.Do.before(this._queueDoBeforeCommand, this, 'command', this),
            Y.Do.before(this._queueDoBeforeQuery, this, 'query', this)
        ];
    },

    /**
    Clears the command queue

    @method _clearCommandQueue
    @protected
    **/
    _clearCommandQueue: function() {
        this._commandQueue = null;
    },

    /**
    Detaches queue events.

    @method _detachQueueEvents
    @protected
    **/
    _detachQueueEvents: function() {
        if (this._queueEvents) {
            new Y.EventHandle(this._queueEvents).detach();
            this._queueEvents = null;
        }
    },

    /**
    Executes all commands on the command queue

    @method _flushCommandQueue
    @protected
    **/
    _flushCommandQueue: function() {
        if (!this._commandQueue) {
            return;
        }

        // need to create a copy because the commandQueue
        // will be flushed after the first command is executed
        var queue = Y.merge(this._commandQueue);

        Y.Object.each(queue, function(value, cmd) {
            this.command(cmd, value);
        }, this);

        this._clearCommandQueue();
    },

    /**
    Adds a command to the queue

    @method _queueCommand
    @protected
    **/
    _queueCommand: function(name, value) {
        var command = this.commands[name];

        if (!this._commandQueue) {
            this._commandQueue = {};
        }

        if (command.style && Y.Lang.isValue(command.style.value)) {
            value = this._commandQueue[name] ? '' : command.style.value;
        }

        this._commandQueue[name] = value;

        return value;
    },

    // -- Protected Event Handlers ---------------------------------------------

    /**
    Handles `keypress` events on the editor

    @param {EventFacade} e
    @protected
    **/
    _onKeyPress: function(e) {
        if (e.metaKey) {
            return;
        }

        var selection = this.selection,
            range = selection.range(),
            node;

        if (range.shrink().isCollapsed() && this._commandQueue) {
            e.preventDefault();

            node = range.insertNode(Y.Node.create(String.fromCharCode(e.charCode)));

            selection.select(range.selectNode(node));

            this._flushCommandQueue();

            selection.select(range.selectNode(node).shrink().collapse());
        } else {
            this._clearCommandQueue();
        }
    },

    /**
    Wrapper for `Editor.Base#_execCommand()`.

    @method _queueBeforeExecStyleCommand
    @param {String} name Command name.
    @param {Boolean|String} value Command value.
    @protected
    **/
    _queueDoBeforeCommand: function (name, value) {
        var styleCmd = this.styleCommands[name],
            range, ret;

        if (styleCmd && 'block' !== styleCmd.type) {
            range = this.selection.range();

            if (range && range.isCollapsed()) {
                ret = this._queueCommand(name, value);
                this._updateSelection({force: true});
                return new Y.Do.Halt('Editor.Queue prevented command', ret);
            }
        } else {
            this._clearCommandQueue();
        }
    },

    /**
    Wrapper for `Editor.Base#_queryCommandValue()`.

    @method _queueDoBeforeQueryCommandValue
    @param {String} name Command name.
    @protected
    **/
    _queueDoBeforeQuery: function (name) {
        var qCmd = this._commandQueue && this._commandQueue[name],
            styleCmd = this.styleCommands[name];

        if (styleCmd && Y.Lang.isValue(qCmd)) { // because qCmd could be ''
            if (Y.Lang.isValue(styleCmd.style.value)) {
                qCmd = qCmd === styleCmd.style.value;
            }

            return new Y.Do.Halt('Editor.Queue prevented query', qCmd);
        }
    }
});

Y.namespace('Editor').Queue = EditorQueue;

}());
<|endoftext|>


<commit_before>import React from 'react';
import { provideHooks } from 'redial';

export default (callback) => (ComposedComponent) => {
  class FetchDataEnhancer extends ComposedComponent {
    render() {
      return (
        <ComposedComponent { ...this.props } />
      );
    }
  }

  return provideHooks({
    fetchData(...args) {
      return callback(...args);
    },
  })(FetchDataEnhancer);
};
<commit_msg>Update FetchDataEnhancer<commit_after>import React from 'react';
import { provideHooks } from 'redial';

export default (callback) => (ComposedComponent) =>
  provideHooks({
    fetchData(...args) {
      return callback(...args);
    },
  })(
    props => <ComposedComponent { ...props } />
  );
<|endoftext|>


<commit_before>import * as ConvBlock from "../Conv/Block.js";

export { Config, Base };

/**
 * A neural network's configuration.
 *
 * A special recommended configuration is 3x3 ShuffleNetV2 without explicit bias (but with implicit bias by cosine activation):
 *   - bChannelShuffler: true
 *   - pointwise1ChannelCountRate: 1
 *   - strAvgMaxConv: "Conv"
 *   - depthwiseFilterHeight: 3
 *   - depthwiseChannelMultiplierBlock0Step0: 1
 *   - bBias: false
 *   - strActivationName: "cos"
 *
 * The cosine activation function can achieve impilcit bias. This is because depthwise and pointwise convolution can easily achieve zero
 * and ( cos( 0 ) == 1 ). A constant value (e.g. 1) becomes an bias of the next convolution. So there is not necessary to use explicit bias
 * which has worse performance (than without it).
 *
 * The recommended sourceChannelCount is 4. This is because source image is usually generated by tf.browser.fromPixels() and it handles
 * RGBA 4 channels faster than RGB 3 channels.
 */
class Config {
  /**
   * @param {number} depthwiseChannelMultiplierBlock0Step0
   *   The depthwise convolution of the first step (Step 0) of the first block (Block 0) will expand input channel by this factor.
   *
   * @see ConvBlock.Base.init
   */
  constructor(
    sourceHeight, sourceWidth, sourceChannelCount = 4,
    stepCountPerBlock,
    bChannelShuffler = true,
    pointwise1ChannelCountRate = 1,
    strAvgMaxConv = "Conv", depthwiseFilterHeight = 3, depthwiseChannelMultiplierBlock0Step0 = 1, bBias = false, strActivationName = "cos" )
  {
    this.sourceHeight = sourceHeight;
    this.sourceWidth = sourceWidth;
    this.sourceChannelCount = sourceChannelCount;
    this.stepCountPerBlock = stepCountPerBlock;
    this.bChannelShuffler = bChannelShuffler;
    this.pointwise1ChannelCountRate = pointwise1ChannelCountRate;
    this.strAvgMaxConv = strAvgMaxConv;
    this.depthwiseFilterHeight = depthwiseFilterHeight;
    this.depthwiseChannelMultiplierBlock0Step0 = depthwiseChannelMultiplierBlock0Step0;
    this.bBias = bBias;
    this.strActivationName = strActivationName;

    this.sourceHeightWidth = [ this.sourceHeight, this.sourceWidth ];
  }

  /**
   * @param {ImageData|HTMLCanvasElement} source_ImageData_or_Canvas
   *   The image or canvas which provides image.
   *
   * @return {tf.tensor3d}
   *   Return the tensor3d which is the scaled image from canvas. Its size will be this.sourceImageHeightWidth. Its channel count
   * will be this.config.sourceChannelCount.
   */
  create_ScaledSourceTensor_from_ImageData_or_Canvas( source_ImageData_or_Canvas ) {

    // Using fromPixels() to get source image so that we can always dispose all tensors (including sourceTensor) except the returning tensor.
    let sourceTensor = tf.browser.fromPixels( source_ImageData_or_Canvas, this.sourceChannelCount );

    // If the size (height x width) is as expected, use it directly.
    if (   ( sourceTensor.shape[ 0 ] == this.sourceHeight )
        && ( sourceTensor.shape[ 1 ] == this.sourceWidth  ) )
      return sourceTensor;

    // Otherwise, resize to the default size (height x width) which is the input image size used for training the neural network.
    let scaledSourceTensor = tf.image.resizeBilinear( sourceTensor, this.sourceHeightWidth, true ); // ( alignCorners = true ) for visual image resizing.
    sourceTensor.dispose();

    return scaledSourceTensor;
  }

  /** The channel count of the first block (Block 0). */
  get channelCountBlock0() {
    return this.sourceChannelCount * this.depthwiseChannelMultiplierBlock0Step0;
  }

}

/**
 * A neural network composes of multiple blocks.
 *
 *
 *
 * @member {Config} config
 *   This neural network's configuration.
 *
 * @member {string} structure
 *   A string denote this neural network's structure (configuration).
 *
 * @member {number} totalChannelExpansionFactor
 *   The final output of this neural network will have ( totalChannelExpansionFactor * sourceChannelCount ) channel count.
 *
 * @member {number[]} sourceImageHeightWidth
 *   The size (i.e. [ height, width ]) of the source image. When apply_and_destroy_or_keep() is called, the input tensor should be this size.
 */
class Base {

  /**
   * @param {Config} config
   *   The configuration of this neural network.
   *
   * @param {boolean} bKeepInputTensor
   *   If true, apply_and_destroy_or_keep() will not dispose inputTensor (i.e. keep).
   *
   * @see ConvBlock.Base.init
   */
  init( config, bKeepInputTensor ) {

    this.disposeTensors();

    this.config = config;
    this.bKeepInputTensor = bKeepInputTensor;

    let targetHeight = 1; // The final output always has ( height x width ) = ( 1 x 1 ), i.e. only one pixel per channel.

    let differenceHeight = config.sourceHeight - targetHeight;
//    let filterWidth = depthwiseFilterHeight;

//  this.depthwiseChannelMultiplierBlock0Step0 = depthwiseChannelMultiplierBlock0Step0;
//    this.channelCountBlock0 = config.sourceChannelCount * config.depthwiseChannelMultiplierBlock0Step0;  // the channel count of the first block (Block 0).

    if ( config.stepCountPerBlock <= 0 ) { // Not ShuffleNetV2, Not MobileNetV2.

      // The height of processed image will be reduced a little for any depthwise filter larger than 1x1.
      let heightReducedPerBlock = config.depthwiseFilterHeight - 1;

      // The block count for reducing sourceHeight to targetHeight by tf.depthwiseConv2d( strides = 1, pad = "valid" ).
      this.blockCount = Math.floor( differenceHeight / heightReducedPerBlock );

      // Channel count only be expanded by channel multiplier of depthwise convolution of step 0 of block 0.
      this.totalChannelExpansionFactor = config.depthwiseChannelMultiplierBlock0Step0;

    } else {  // ShuffleNetV2 or MobileNetV2. Halven per block.

      // The block count for reducing sourceHeight to targetHeight by tf.depthwiseConv2d( strides = 2, pad = "same" ).
//      this.blockCount = Math.floor( Math.log2( sourceHeight ) );
      this.blockCount = Math.ceil( Math.log2( config.sourceHeight ) );

//!!! wrong
//       // Channel count is expanded both by channel multiplier of depthwise convolution of step 0 of block 0
//       // and by every block (half height x width and double channel count).
//       this.totalChannelExpansionFactor = depthwiseChannelMultiplierBlock0Step0 * Math.pow( 2, this.blockCount );

      // Channel count is expanded by every block (half height x width and double channel count).
      this.totalChannelExpansionFactor = Math.pow( 2, this.blockCount );
    }

    let nextBlockInputChannelCount = config.sourceChannelCount;
    let nextBlockDepthwiseChannelMultiplier = config.depthwiseChannelMultiplierBlock0Step0; // Only block 0 can have ( depthwise channel multiplier > 1 ).

    let nextKeepInputTensor = bKeepInputTensor; // Only step 0 may or may not keep the input tensor according to caller's necessary.

    this.blocks = new Array( this.blockCount );
    for ( let i = 0; i < this.blockCount; ++i )
    {
      let block = new ConvBlock.Base();
      block.init(
        config.sourceHeight, config.sourceWidth, nextBlockInputChannelCount,
        config.stepCountPerBlock,
        config.bChannelShuffler,
        config.pointwise1ChannelCountRate,
        config.strAvgMaxConv, config.depthwiseFilterHeight, nextBlockDepthwiseChannelMultiplier, config.bBias, config.strActivationName,
        nextKeepInputTensor
      );

      this.blocks[ i ] = block;
      nextBlockInputChannelCount = block.outputChannelCount; // Using previous block's output channel count as next block's input channel count.
      nextBlockDepthwiseChannelMultiplier = 1;               // Except block 0, all other blocks' depthwise channel multiplier should be 1.
      nextKeepInputTensor = false;                           // All blocks (except block 0) should not keep (and should dispose) the input tensor.
    }

    let block0 = this.blocks[ 0 ];

    // e.g. "C24_24__DConv_101x101_DBias_RELU__PConv_PBias_RELU__Block_1__Step_1"
    this.structure = `C${config.sourceChannelCount}_${config.channelCountBlock0}`

      + `${ ( block0.step0.bPointwise1 ) ? "__PConv1(x" + config.pointwise1ChannelCountRate + ")" : "" }`
      + `${ ( block0.step0.bPointwise1 && block0.step0.bPointwise1Bias ) ? ( "_PBias1" ) : "" }`
      + `${ ( block0.step0.bPointwise1 && block0.step0.pointwise1ActivationFunction ) ? ( "_" + block0.step0.pointwise1ActivationName ) : "" }`

      + `${ ( block0.step0.bDepthwise ) ? `__D${config.strAvgMaxConv}_${config.depthwiseFilterHeight}x${config.depthwiseFilterHeight}` : "" }`
      + `${ ( block0.step0.bDepthwise && block0.step0.bDepthwiseBias ) ? ( "_DBias" ) : "" }`
      + `${ ( block0.step0.bDepthwise && block0.step0.depthwiseActivationFunction ) ? ( "_" + config.strActivationName ) : "" }`

      + `${ ( block0.step0.bPointwise2 ) ? "__PConv2" : "" }`
      + `${ ( block0.step0.bPointwise2 && block0.step0.bPointwise2Bias ) ? ( "_PBias2" ) : "" }`
      + `${ ( block0.step0.bPointwise2 && block0.step0.pointwise2ActivationFunction ) ? ( "_" + block0.step0.pointwise2ActivationName ) : "" }`

      + `__Block_${this.blockCount}`
      + `__Step_${config.stepCountPerBlock}`
      + `${ ( config.bChannelShuffler ) ? "__Shuffle" : ( ( config.stepCountPerBlock > 0 ) ? "__AddInput" : "" ) }`
      //+ `${ ( bKeepInputTensor ) ? "__KeepInput" : "" }`
    ;

    this.sourceImageHeightWidth = [ block0.sourceHeight, block0.sourceWidth ];
  }

  disposeTensors() {
    if ( this.blocks ) {
      for ( let i = 0; i < this.blocks.length; ++i ) {
        let block = this.blocks[ i ];
        block.disposeTensors();
      }
      this.blocks = null;
    }
  }

  /**
   *
   * @param {tf.tensor3d} inputTensor
   *   The image which will be processed. This inputTensor may or may not be disposed according to init()'s bKeepInputTensor.
   * Its size should be this.sourceImageHeightWidth.
   *
   * @param {boolean} bReturn
   *   If true, the result tensor will be returned. Otherwise, the result tensor will be disposed.
   *
   * @return {tf.tensor3d}
   *   If ( bReturn == true ), return the result (new) tensor. If ( bReturn == false ), the result tensor will be disposed and nothing
   * will be returned. No matter in which case, all other intermediate tensors were disposed.
   */
  apply_and_destroy_or_keep( inputTensor, bReturn ) {
    let t = inputTensor;

    let block;
    for ( let i = 0; i < this.blocks.length; ++i ) {
      block = this.blocks[ i ];
      t = block.apply_and_destroy_or_keep( t );
    }

    if ( bReturn )
      return t;
    else
      t.dispose();
  }

}
<commit_msg>Update Net.js<commit_after>import * as ConvBlock from "../Conv/Block.js";

export { Config, Base };

/**
 * A neural network's configuration.
 *
 * A special recommended configuration is 3x3 ShuffleNetV2 without explicit bias (but with implicit bias by cosine activation):
 *   - bChannelShuffler: true
 *   - pointwise1ChannelCountRate: 1
 *   - strAvgMaxConv: "Conv"
 *   - depthwiseFilterHeight: 3
 *   - depthwiseChannelMultiplierBlock0Step0: 1
 *   - bBias: false
 *   - strActivationName: "cos"
 *
 * The cosine activation function can achieve impilcit bias. This is because depthwise and pointwise convolution can easily achieve zero
 * and ( cos( 0 ) == 1 ). A constant value (e.g. 1) becomes an bias of the next convolution. So there is not necessary to use explicit bias
 * which has worse performance (than without it).
 *
 * The recommended sourceChannelCount is 4. This is because source image is usually generated by tf.browser.fromPixels() and it handles
 * RGBA 4 channels faster than RGB 3 channels.
 */
class Config {
  /**
   * @param {number} depthwiseChannelMultiplierBlock0Step0
   *   The depthwise convolution of the first step (Step 0) of the first block (Block 0) will expand input channel by this factor.
   *
   * @see ConvBlock.Base.init
   */
  constructor(
    sourceHeight, sourceWidth, sourceChannelCount = 4,
    stepCountPerBlock,
    bChannelShuffler = true,
    pointwise1ChannelCountRate = 1,
    strAvgMaxConv = "Conv", depthwiseFilterHeight = 3, depthwiseChannelMultiplierBlock0Step0 = 1, bBias = false, strActivationName = "cos" )
  {
    this.sourceHeight = sourceHeight;
    this.sourceWidth = sourceWidth;
    this.sourceChannelCount = sourceChannelCount;
    this.stepCountPerBlock = stepCountPerBlock;
    this.bChannelShuffler = bChannelShuffler;
    this.pointwise1ChannelCountRate = pointwise1ChannelCountRate;
    this.strAvgMaxConv = strAvgMaxConv;
    this.depthwiseFilterHeight = depthwiseFilterHeight;
    this.depthwiseChannelMultiplierBlock0Step0 = depthwiseChannelMultiplierBlock0Step0;
    this.bBias = bBias;
    this.strActivationName = strActivationName;

    this.sourceHeightWidth = [ this.sourceHeight, this.sourceWidth ];
  }

  /**
   * @param {ImageData|HTMLCanvasElement} source_ImageData_or_Canvas
   *   The image or canvas which provides image.
   *
   * @return {tf.tensor3d}
   *   Return the tensor3d which is the scaled image from canvas. Its size will be this.sourceImageHeightWidth. Its channel count
   * will be this.config.sourceChannelCount.
   */
  create_ScaledSourceTensor_from_ImageData_or_Canvas( source_ImageData_or_Canvas ) {

    let sourceTensor = tf.browser.fromPixels( source_ImageData_or_Canvas, this.sourceChannelCount );

    // If the size (height x width) is as expected, use it directly.
    if (   ( sourceTensor.shape[ 0 ] == this.sourceHeight )
        && ( sourceTensor.shape[ 1 ] == this.sourceWidth  ) )
      return sourceTensor;

    // Otherwise, resize to the default size (height x width) which is the input image size used for training the neural network.
    let scaledSourceTensor = tf.image.resizeBilinear( sourceTensor, this.sourceHeightWidth, true ); // ( alignCorners = true ) for visual image resizing.
    sourceTensor.dispose();

    return scaledSourceTensor;
  }

  /** The channel count of the first block (Block 0). */
  get channelCountBlock0() {
    return this.sourceChannelCount * this.depthwiseChannelMultiplierBlock0Step0;
  }

}

/**
 * A neural network composes of multiple blocks.
 *
 *
 *
 * @member {Config} config
 *   This neural network's configuration.
 *
 * @member {string} structure
 *   A string denote this neural network's structure (configuration).
 *
 * @member {number} totalChannelExpansionFactor
 *   The final output of this neural network will have ( totalChannelExpansionFactor * sourceChannelCount ) channel count.
 *
 * @member {number[]} sourceImageHeightWidth
 *   The size (i.e. [ height, width ]) of the source image. When apply_and_destroy_or_keep() is called, the input tensor should be this size.
 */
class Base {

  /**
   * @param {Config} config
   *   The configuration of this neural network.
   *
   * @param {boolean} bKeepInputTensor
   *   If true, apply_and_destroy_or_keep() will not dispose inputTensor (i.e. keep).
   *
   * @see ConvBlock.Base.init
   */
  init( config, bKeepInputTensor ) {

    this.disposeTensors();

    this.config = config;
    this.bKeepInputTensor = bKeepInputTensor;

    let targetHeight = 1; // The final output always has ( height x width ) = ( 1 x 1 ), i.e. only one pixel per channel.

    let differenceHeight = config.sourceHeight - targetHeight;
//    let filterWidth = depthwiseFilterHeight;

//  this.depthwiseChannelMultiplierBlock0Step0 = depthwiseChannelMultiplierBlock0Step0;
//    this.channelCountBlock0 = config.sourceChannelCount * config.depthwiseChannelMultiplierBlock0Step0;  // the channel count of the first block (Block 0).

    if ( config.stepCountPerBlock <= 0 ) { // Not ShuffleNetV2, Not MobileNetV2.

      // The height of processed image will be reduced a little for any depthwise filter larger than 1x1.
      let heightReducedPerBlock = config.depthwiseFilterHeight - 1;

      // The block count for reducing sourceHeight to targetHeight by tf.depthwiseConv2d( strides = 1, pad = "valid" ).
      this.blockCount = Math.floor( differenceHeight / heightReducedPerBlock );

      // Channel count only be expanded by channel multiplier of depthwise convolution of step 0 of block 0.
      this.totalChannelExpansionFactor = config.depthwiseChannelMultiplierBlock0Step0;

    } else {  // ShuffleNetV2 or MobileNetV2. Halven per block.

      // The block count for reducing sourceHeight to targetHeight by tf.depthwiseConv2d( strides = 2, pad = "same" ).
//      this.blockCount = Math.floor( Math.log2( sourceHeight ) );
      this.blockCount = Math.ceil( Math.log2( config.sourceHeight ) );

//!!! wrong
//       // Channel count is expanded both by channel multiplier of depthwise convolution of step 0 of block 0
//       // and by every block (half height x width and double channel count).
//       this.totalChannelExpansionFactor = depthwiseChannelMultiplierBlock0Step0 * Math.pow( 2, this.blockCount );

      // Channel count is expanded by every block (half height x width and double channel count).
      this.totalChannelExpansionFactor = Math.pow( 2, this.blockCount );
    }

    let nextBlockInputChannelCount = config.sourceChannelCount;
    let nextBlockDepthwiseChannelMultiplier = config.depthwiseChannelMultiplierBlock0Step0; // Only block 0 can have ( depthwise channel multiplier > 1 ).

    let nextKeepInputTensor = bKeepInputTensor; // Only step 0 may or may not keep the input tensor according to caller's necessary.

    this.blocks = new Array( this.blockCount );
    for ( let i = 0; i < this.blockCount; ++i )
    {
      let block = new ConvBlock.Base();
      block.init(
        config.sourceHeight, config.sourceWidth, nextBlockInputChannelCount,
        config.stepCountPerBlock,
        config.bChannelShuffler,
        config.pointwise1ChannelCountRate,
        config.strAvgMaxConv, config.depthwiseFilterHeight, nextBlockDepthwiseChannelMultiplier, config.bBias, config.strActivationName,
        nextKeepInputTensor
      );

      this.blocks[ i ] = block;
      nextBlockInputChannelCount = block.outputChannelCount; // Using previous block's output channel count as next block's input channel count.
      nextBlockDepthwiseChannelMultiplier = 1;               // Except block 0, all other blocks' depthwise channel multiplier should be 1.
      nextKeepInputTensor = false;                           // All blocks (except block 0) should not keep (and should dispose) the input tensor.
    }

    let block0 = this.blocks[ 0 ];

    // e.g. "C24_24__DConv_101x101_DBias_RELU__PConv_PBias_RELU__Block_1__Step_1"
    this.structure = `C${config.sourceChannelCount}_${config.channelCountBlock0}`

      + `${ ( block0.step0.bPointwise1 ) ? "__PConv1(x" + config.pointwise1ChannelCountRate + ")" : "" }`
      + `${ ( block0.step0.bPointwise1 && block0.step0.bPointwise1Bias ) ? ( "_PBias1" ) : "" }`
      + `${ ( block0.step0.bPointwise1 && block0.step0.pointwise1ActivationFunction ) ? ( "_" + block0.step0.pointwise1ActivationName ) : "" }`

      + `${ ( block0.step0.bDepthwise ) ? `__D${config.strAvgMaxConv}_${config.depthwiseFilterHeight}x${config.depthwiseFilterHeight}` : "" }`
      + `${ ( block0.step0.bDepthwise && block0.step0.bDepthwiseBias ) ? ( "_DBias" ) : "" }`
      + `${ ( block0.step0.bDepthwise && block0.step0.depthwiseActivationFunction ) ? ( "_" + config.strActivationName ) : "" }`

      + `${ ( block0.step0.bPointwise2 ) ? "__PConv2" : "" }`
      + `${ ( block0.step0.bPointwise2 && block0.step0.bPointwise2Bias ) ? ( "_PBias2" ) : "" }`
      + `${ ( block0.step0.bPointwise2 && block0.step0.pointwise2ActivationFunction ) ? ( "_" + block0.step0.pointwise2ActivationName ) : "" }`

      + `__Block_${this.blockCount}`
      + `__Step_${config.stepCountPerBlock}`
      + `${ ( config.bChannelShuffler ) ? "__Shuffle" : ( ( config.stepCountPerBlock > 0 ) ? "__AddInput" : "" ) }`
      //+ `${ ( bKeepInputTensor ) ? "__KeepInput" : "" }`
    ;

    this.sourceImageHeightWidth = [ block0.sourceHeight, block0.sourceWidth ];
  }

  disposeTensors() {
    if ( this.blocks ) {
      for ( let i = 0; i < this.blocks.length; ++i ) {
        let block = this.blocks[ i ];
        block.disposeTensors();
      }
      this.blocks = null;
    }
  }

  /**
   *
   * @param {tf.tensor3d} inputTensor
   *   The image which will be processed. This inputTensor may or may not be disposed according to init()'s bKeepInputTensor.
   * Its size should be this.sourceImageHeightWidth.
   *
   * @param {boolean} bReturn
   *   If true, the result tensor will be returned. Otherwise, the result tensor will be disposed.
   *
   * @return {tf.tensor3d}
   *   If ( bReturn == true ), return the result (new) tensor. If ( bReturn == false ), the result tensor will be disposed and nothing
   * will be returned. No matter in which case, all other intermediate tensors were disposed.
   */
  apply_and_destroy_or_keep( inputTensor, bReturn ) {
    let t = inputTensor;

    let block;
    for ( let i = 0; i < this.blocks.length; ++i ) {
      block = this.blocks[ i ];
      t = block.apply_and_destroy_or_keep( t );
    }

    if ( bReturn )
      return t;
    else
      t.dispose();
  }

}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.provide("frappe.perm");

// backward compatibilty
Object.assign(window, {
	READ: "read",
	WRITE: "write",
	CREATE: "create",
	DELETE: "delete",
	SUBMIT: "submit",
	CANCEL: "cancel",
	AMEND: "amend",
});

$.extend(frappe.perm, {
	rights: [
		"select",
		"read",
		"write",
		"create",
		"delete",
		"submit",
		"cancel",
		"amend",
		"report",
		"import",
		"export",
		"print",
		"email",
		"share",
		"set_user_permissions",
	],

	doctype_perm: {},

	has_perm: (doctype, permlevel, ptype, doc) => {
		if (!permlevel) permlevel = 0;
		if (!frappe.perm.doctype_perm[doctype] && !doc) {
			frappe.perm.doctype_perm[doctype] = frappe.perm.get_perm(doctype);
		}

		// if document object is passed, get fresh doc based perms
		// (with ownership and user perms applied) else stale doctype perms
		let perms = doc ? frappe.perm.get_perm(doctype, doc) : frappe.perm.doctype_perm[doctype];

		if (!perms || !perms[permlevel]) return false;

		return !!perms[permlevel][ptype];
	},

	get_perm: (doctype, doc) => {
		let perm = [{ read: 0, permlevel: 0 }];

		let meta = frappe.get_doc("DocType", doctype);
		const user = frappe.session.user;

		if (user === "Administrator" || frappe.user_roles.includes("Administrator")) {
			perm[0].read = 1;
		}

		if (!meta) return perm;

		perm = frappe.perm.get_role_permissions(meta);

		if (doc) {
			// apply user permissions via docinfo (which is processed server-side)
			let docinfo = frappe.model.get_docinfo(doctype, doc.name);
			if (docinfo && docinfo.permissions) {
				Object.keys(docinfo.permissions).forEach((ptype) => {
					perm[0][ptype] = docinfo.permissions[ptype];
				});
			}

			// if owner
			if (!$.isEmptyObject(perm[0].if_owner)) {
				if (doc.owner === user) {
					$.extend(perm[0], perm[0].if_owner);
				} else {
					// not owner, remove permissions
					$.each(perm[0].if_owner, (ptype) => {
						if (perm[0].if_owner[ptype]) {
							perm[0][ptype] = 0;
						}
					});
				}
			}

			// apply permissions from shared
			if (docinfo && docinfo.shared) {
				for (let i = 0; i < docinfo.shared.length; i++) {
					let s = docinfo.shared[i];
					if (s.user === user) {
						perm[0]["read"] = perm[0]["read"] || s.read;
						perm[0]["write"] = perm[0]["write"] || s.write;
						perm[0]["submit"] = perm[0]["submit"] || s.submit;
						perm[0]["share"] = perm[0]["share"] || s.share;

						if (s.read) {
							// also give print, email permissions if read
							// and these permissions exist at level [0]
							perm[0].email =
								frappe.boot.user.can_email.indexOf(doctype) !== -1 ? 1 : 0;
							perm[0].print =
								frappe.boot.user.can_print.indexOf(doctype) !== -1 ? 1 : 0;
						}
					}
				}
			}
		}

		if (frappe.model.can_read(doctype) && !perm[0].read) {
			// read via sharing
			perm[0].read = 1;
		}

		return perm;
	},

	get_role_permissions: (meta) => {
		/** Returns a `dict` of evaluated Role Permissions like:
		{
			"read": 1,
			"write": 0,
			"if_owner": [if "if_owner" is enabled]
				{
					"read": 1,
					"write": 0
				}
		} */
		let perm = [{ read: 0, permlevel: 0 }];

		(meta.permissions || []).forEach((p) => {
			let permlevel = cint(p.permlevel);
			if (!perm[permlevel]) {
				perm[permlevel] = {};
				perm[permlevel]["permlevel"] = permlevel;
			}

			// if user has this role
			if (frappe.user_roles.includes(p.role)) {
				frappe.perm.rights.forEach((right) => {
					let value = perm[permlevel][right] || p[right] || 0;

					if (p.if_owner && value) {
						// if_owner is enabled for perm,
						// construct perm object inside "if_owner" property
						if (!perm[permlevel]["if_owner"]) {
							perm[permlevel]["if_owner"] = {}
						}
						perm[permlevel]["if_owner"][right] = value;
					} else if (value) {
						perm[permlevel][right] = value;
					}
				});
			}
		});

		// fill gaps with empty object
		perm = perm.map((p) => p || {});
		return perm;
	},

	get_match_rules: (doctype, ptype) => {
		let match_rules = [];

		if (!ptype) ptype = "read";

		let perm = frappe.perm.get_perm(doctype);

		let user_permissions = frappe.defaults.get_user_permissions();

		if (user_permissions && !$.isEmptyObject(user_permissions)) {
			let rules = {};
			let fields_to_check = frappe.meta.get_fields_to_check_permissions(doctype);
			$.each(fields_to_check, (i, df) => {
				const user_permissions_for_doctype = user_permissions[df.options] || [];
				const allowed_records = frappe.perm.get_allowed_docs_for_doctype(
					user_permissions_for_doctype,
					doctype
				);
				if (allowed_records.length) {
					rules[df.label] = allowed_records;
				}
			});
			if (!$.isEmptyObject(rules)) {
				match_rules.push(rules);
			}
		}

		if (perm[0].if_owner && perm[0].read) {
			match_rules.push({ Owner: frappe.session.user });
		}
		return match_rules;
	},

	get_field_display_status: (df, doc, perm, explain) => {
		// returns the display status of a particular field
		// returns one of "Read", "Write" or "None"
		if (!perm && doc) {
			perm = frappe.perm.get_perm(doc.doctype, doc);
		}

		if (!perm) {
			return df && (cint(df.hidden) || cint(df.hidden_due_to_dependency)) ? "None" : "Write";
		}

		if (!df.permlevel) df.permlevel = 0;
		let p = perm[df.permlevel];
		let status = "None";

		// permission
		if (p) {
			if (p.write && !df.disabled) {
				status = "Write";
			} else if (p.read) {
				status = "Read";
			}
		}
		if (explain) console.log("By Permission:" + status);

		// hidden
		if (cint(df.hidden)) status = "None";
		if (explain) console.log("By Hidden:" + status);

		// hidden due to dependency
		if (cint(df.hidden_due_to_dependency)) status = "None";
		if (explain) console.log("By Hidden Due To Dependency:" + status);

		if (!doc) {
			return status;
		}

		// submit
		if (status === "Write" && cint(doc.docstatus) > 0) status = "Read";
		if (explain) console.log("By Submit:" + status);

		// allow on submit
		// let allow_on_submit = df.fieldtype==="Table" ? 0 : cint(df.allow_on_submit);
		let allow_on_submit = cint(df.allow_on_submit);
		if (status === "Read" && allow_on_submit && cint(doc.docstatus) === 1 && p.write) {
			status = "Write";
		}
		if (explain) console.log("By Allow on Submit:" + status);

		// workflow state
		if (status === "Read" && cur_frm && cur_frm.state_fieldname) {
			// fields updated by workflow must be read-only
			if (
				cint(cur_frm.read_only) ||
				in_list(cur_frm.states.update_fields, df.fieldname) ||
				df.fieldname == cur_frm.state_fieldname
			) {
				status = "Read";
			}
		}
		if (explain) console.log("By Workflow:" + status);

		// read only field is checked
		if (status === "Write" && (cint(df.read_only) || df.fieldtype === "Read Only")) {
			status = "Read";
		}
		if (explain) console.log("By Read Only:" + status);

		if (status === "Write" && df.set_only_once && !doc.__islocal) {
			status = "Read";
		}
		if (explain) console.log("By Set Only Once:" + status);

		return status;
	},

	is_visible: (df, doc, perm) => {
		if (typeof df === "string") {
			// df is fieldname
			df = frappe.meta.get_docfield(doc.doctype, df, doc.parent || doc.name);
		}

		let status = frappe.perm.get_field_display_status(df, doc, perm);

		return status === "None" ? false : true;
	},

	get_allowed_docs_for_doctype: (user_permissions, doctype) => {
		// returns docs from the list of user permissions that are allowed under provided doctype
		return frappe.perm.filter_allowed_docs_for_doctype(user_permissions, doctype, false);
	},

	filter_allowed_docs_for_doctype: (user_permissions, doctype, with_default_doc = true) => {
		// returns docs from the list of user permissions that are allowed under provided doctype
		// also returns default doc when with_default_doc is set
		const filtered_perms = (user_permissions || []).filter((perm) => {
			return perm.applicable_for === doctype || !perm.applicable_for;
		});

		const allowed_docs = filtered_perms.map((perm) => perm.doc);

		if (with_default_doc) {
			const default_doc =
				allowed_docs.length === 1
					? allowed_docs
					: filtered_perms.filter((perm) => perm.is_default).map((record) => record.doc);

			return {
				allowed_records: allowed_docs,
				default_doc: default_doc[0],
			};
		} else {
			return allowed_docs;
		}
	},
});
<commit_msg>fix: correct logic for `if_owner` and refactor<commit_after>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.provide("frappe.perm");

// backward compatibilty
Object.assign(window, {
	READ: "read",
	WRITE: "write",
	CREATE: "create",
	DELETE: "delete",
	SUBMIT: "submit",
	CANCEL: "cancel",
	AMEND: "amend",
});

$.extend(frappe.perm, {
	rights: [
		"select",
		"read",
		"write",
		"create",
		"delete",
		"submit",
		"cancel",
		"amend",
		"report",
		"import",
		"export",
		"print",
		"email",
		"share",
		"set_user_permissions",
	],

	doctype_perm: {},

	has_perm: (doctype, permlevel, ptype, doc) => {
		if (!permlevel) permlevel = 0;

		// if document object is passed, get fresh doc based perms
		// (with ownership and user perms applied) else cached doctype perms
		const perms = doc
			? frappe.perm.get_perm(doctype, doc)
			: (frappe.perm.doctype_perm[doctype] ??= frappe.perm.get_perm(doctype));

		return !!perms?.[permlevel]?.[ptype];
	},

	get_perm: (doctype, doc) => {
		let perm = [{ read: 0, permlevel: 0 }];

		let meta = frappe.get_doc("DocType", doctype);
		const user = frappe.session.user;

		if (user === "Administrator" || frappe.user_roles.includes("Administrator")) {
			perm[0].read = 1;
		}

		if (!meta) return perm;

		perm = frappe.perm.get_role_permissions(meta);
		const base_perm = perm[0];

		if (doc) {
			// apply user permissions via docinfo (which is processed server-side)
			let docinfo = frappe.model.get_docinfo(doctype, doc.name);
			if (docinfo && docinfo.permissions) {
				Object.keys(docinfo.permissions).forEach((ptype) => {
					base_perm[ptype] = docinfo.permissions[ptype];
				});
			}

			// if owner
			if (doc.owner !== user) {
				for (const right of frappe.perm.rights) {
					if (base_perm[right] && !base_perm.rights_without_if_owner.has(right)) {
						base_perm[right] = 0;
					}
				}
			}

			// apply permissions from shared
			if (docinfo && docinfo.shared) {
				for (const s of docinfo.shared) {
					if (s.user !== user) continue;

					for (const right of ["read", "write", "submit", "share"]) {
						if (!base_perm[right]) base_perm[right] = s[right];
					}

					if (s.read) {
						// also give print, email permissions if read
						// and these permissions exist at level [0]
						base_perm.email =
							frappe.boot.user.can_email.indexOf(doctype) !== -1 ? 1 : 0;
						base_perm.print =
							frappe.boot.user.can_print.indexOf(doctype) !== -1 ? 1 : 0;
					}
				}
			}
		}

		if (frappe.model.can_read(doctype) && !base_perm.read) {
			// read via sharing
			base_perm.read = 1;
		}

		return perm;
	},

	get_role_permissions: (meta) => {
		/** Returns a `dict` of evaluated Role Permissions like:
		{
			"read": 1,
			"write": 0,
			"rights_without_if_owner": {"read", "write"}  // for permlevel 0
		}
		*/

		let perm = [{ read: 0, permlevel: 0 }];

		(meta.permissions || []).forEach((p) => {
			const permlevel = cint(p.permlevel);
			const current_perm = (perm[permlevel] ??= { permlevel });

			if (permlevel === 0) {
				current_perm.rights_without_if_owner ??= new Set();
			}

			// if user has this role
			if (frappe.user_roles.includes(p.role)) {
				frappe.perm.rights.forEach((right) => {
					if (!p[right]) return;

					current_perm[right] = 1;

					if (permlevel === 0 && !p.if_owner) {
						current_perm.rights_without_if_owner.add(right);
					}
				});
			}
		});

		// fill gaps with empty object
		perm = perm.map((p) => p || {});
		return perm;
	},

	get_match_rules: (doctype, ptype) => {
		let match_rules = [];

		if (!ptype) ptype = "read";

		let perm = frappe.perm.get_perm(doctype);

		let user_permissions = frappe.defaults.get_user_permissions();

		if (user_permissions && !$.isEmptyObject(user_permissions)) {
			let rules = {};
			let fields_to_check = frappe.meta.get_fields_to_check_permissions(doctype);
			$.each(fields_to_check, (i, df) => {
				const user_permissions_for_doctype = user_permissions[df.options] || [];
				const allowed_records = frappe.perm.get_allowed_docs_for_doctype(
					user_permissions_for_doctype,
					doctype
				);
				if (allowed_records.length) {
					rules[df.label] = allowed_records;
				}
			});
			if (!$.isEmptyObject(rules)) {
				match_rules.push(rules);
			}
		}

		const base_perm = perm[0];
		if (base_perm.read && !base_perm.rights_without_if_owner.has("read")) {
			match_rules.push({ Owner: frappe.session.user });
		}
		return match_rules;
	},

	get_field_display_status: (df, doc, perm, explain) => {
		// returns the display status of a particular field
		// returns one of "Read", "Write" or "None"
		if (!perm && doc) {
			perm = frappe.perm.get_perm(doc.doctype, doc);
		}

		if (!perm) {
			return df && (cint(df.hidden) || cint(df.hidden_due_to_dependency)) ? "None" : "Write";
		}

		if (!df.permlevel) df.permlevel = 0;
		let p = perm[df.permlevel];
		let status = "None";

		// permission
		if (p) {
			if (p.write && !df.disabled) {
				status = "Write";
			} else if (p.read) {
				status = "Read";
			}
		}
		if (explain) console.log("By Permission:" + status);

		// hidden
		if (cint(df.hidden)) status = "None";
		if (explain) console.log("By Hidden:" + status);

		// hidden due to dependency
		if (cint(df.hidden_due_to_dependency)) status = "None";
		if (explain) console.log("By Hidden Due To Dependency:" + status);

		if (!doc) {
			return status;
		}

		// submit
		if (status === "Write" && cint(doc.docstatus) > 0) status = "Read";
		if (explain) console.log("By Submit:" + status);

		// allow on submit
		// let allow_on_submit = df.fieldtype==="Table" ? 0 : cint(df.allow_on_submit);
		let allow_on_submit = cint(df.allow_on_submit);
		if (status === "Read" && allow_on_submit && cint(doc.docstatus) === 1 && p.write) {
			status = "Write";
		}
		if (explain) console.log("By Allow on Submit:" + status);

		// workflow state
		if (status === "Read" && cur_frm && cur_frm.state_fieldname) {
			// fields updated by workflow must be read-only
			if (
				cint(cur_frm.read_only) ||
				in_list(cur_frm.states.update_fields, df.fieldname) ||
				df.fieldname == cur_frm.state_fieldname
			) {
				status = "Read";
			}
		}
		if (explain) console.log("By Workflow:" + status);

		// read only field is checked
		if (status === "Write" && (cint(df.read_only) || df.fieldtype === "Read Only")) {
			status = "Read";
		}
		if (explain) console.log("By Read Only:" + status);

		if (status === "Write" && df.set_only_once && !doc.__islocal) {
			status = "Read";
		}
		if (explain) console.log("By Set Only Once:" + status);

		return status;
	},

	is_visible: (df, doc, perm) => {
		if (typeof df === "string") {
			// df is fieldname
			df = frappe.meta.get_docfield(doc.doctype, df, doc.parent || doc.name);
		}

		let status = frappe.perm.get_field_display_status(df, doc, perm);

		return status === "None" ? false : true;
	},

	get_allowed_docs_for_doctype: (user_permissions, doctype) => {
		// returns docs from the list of user permissions that are allowed under provided doctype
		return frappe.perm.filter_allowed_docs_for_doctype(user_permissions, doctype, false);
	},

	filter_allowed_docs_for_doctype: (user_permissions, doctype, with_default_doc = true) => {
		// returns docs from the list of user permissions that are allowed under provided doctype
		// also returns default doc when with_default_doc is set
		const filtered_perms = (user_permissions || []).filter((perm) => {
			return perm.applicable_for === doctype || !perm.applicable_for;
		});

		const allowed_docs = filtered_perms.map((perm) => perm.doc);

		if (with_default_doc) {
			const default_doc =
				allowed_docs.length === 1
					? allowed_docs
					: filtered_perms.filter((perm) => perm.is_default).map((record) => record.doc);

			return {
				allowed_records: allowed_docs,
				default_doc: default_doc[0],
			};
		} else {
			return allowed_docs;
		}
	},
});
<|endoftext|>


<commit_before>////////////////////////////////////////////////
// data processing
////////////////////////////////////////////////

var fs = require('fs');
var path = require('path');
var dataConfig = require('../data/config/data.js');
const csv = require('csvtojson');
const _ = require('lodash');

// return true if convertable to number
function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
}

// transform csv2json array to id: {y_2012: value} object format
function jsonTransform(jsonArray) {
    var jsonOut = {};
    for (var i = 0; i < jsonArray.length; i++) {
        jsonOut[jsonArray[i]["id"]] = {};
        for (var key in jsonArray[i]) {
            if (key !== 'id') {
                if (isNumeric(jsonArray[i][key])) {
                    jsonOut[jsonArray[i]["id"]][key] = Number(jsonArray[i][key]);
                } else {
                    jsonOut[jsonArray[i]["id"]][key] = null;
                }
            }
        }
    }
    return jsonOut;
}

var dest = "./public/data/metric";

_.each(dataConfig, function(m) {
    if (m.type === "sum") {
        csv()
            .fromFile('data/metric/r' + m.metric + '.csv')
            .on('end_parsed', (jsonObj)=>{
                let outJSON= {};
                outJSON["map"] = jsonTransform(jsonObj);

                if (m.accuracy) {
                    csv()
                        .fromFile('data/metric/m' + m.metric + '-accuracy.csv')
                        .on('end_parsed', (jsonObj)=>{
                            outJSON["a"] = jsonTransform(jsonObj);
                            fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
                        })
                        .on('done',(error)=>{
                            if (error) console.log(error);
                        });
                } else {
                    fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
                }
            })
            .on('done',(error)=>{
                if (error) console.log(error);
            });
    }
    if (m.type === "mean") {
        csv()
            .fromFile('data/metric/n' + m.metric + '.csv')
            .on('end_parsed', (jsonObj)=>{
                let outJSON= {};
                outJSON["map"] = jsonTransform(jsonObj);

                if (m.accuracy) {
                    csv()
                        .fromFile('data/metric/m' + m.metric + '-accuracy.csv')
                        .on('end_parsed', (jsonObj)=>{
                            outJSON["a"] = jsonTransform(jsonObj);
                            fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
                        })
                        .on('done',(error)=>{
                            if (error) console.log(error);
                        });
                } else {
                    fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
                }
            })
            .on('done',(error)=>{
                if (error) console.log(error);
            });
    }
    if (m.type === "weighted") {
        csv()
            .fromFile('data/metric/r' + m.metric + '.csv')
            .on('end_parsed', (jsonObj)=>{
                let outJSON= {};
                let jsonArrayR = jsonTransform(jsonObj);

                csv()
                    .fromFile('data/metric/d' + m.metric + '.csv')
                    .on('end_parsed', (jsonObj)=>{
                        var jsonArrayD = jsonTransform(jsonObj);
                        for (key in jsonArrayR) {
                            for (key2 in jsonArrayR[key]) {
                                if (isNumeric(jsonArrayR[key][key2]) && isNumeric(jsonArrayD[key][key2])) {
                                    jsonArrayR[key][key2] = Math.round((jsonArrayR[key][key2] / jsonArrayD[key][key2]) * 1000) / 1000;
                                } else {
                                    jsonArrayR[key][key2] = null;
                                }
                            }
                        }
                        outJSON["w"] = jsonArrayD;
                        outJSON["map"] = jsonArrayR;
                        if (m.accuracy) {
                            csv()
                                .fromFile('data/metric/m' + m.metric + '-accuracy.csv')
                                .on('end_parsed', (jsonObj)=>{
                                    outJSON["a"] = jsonTransform(jsonObj);
                                    fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
                                })
                                .on('done',(error)=>{
                                    if (error) console.log(error);
                                });
                        } else {
                            fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
                        }

                    })
                    .on('done',(error)=>{
                        if (error) console.log(error);
                    });
            })
            .on('done',(error)=>{
                if (error) console.log(error);
            });
    }
});

// // csv to jxon
// gulp.task('csv2json', ['clean'], function() {
//     return gulp.src('data/metric/*.csv')
//         .pipe(convert({
//             from: 'csv',
//             to: 'json'
//         }))
//         .pipe(gulp.dest('tmp/'));
// });

// // convert/move json files
// gulp.task('transform', ['clean', 'csv2json'], function(cb) {
//     var dest = "./public/data/metric";
//     mkdirp(dest, function() {
//         _.each(dataConfig, function(m) {
//             if (m.type === "sum") {
//                 let r = require('./tmp/r' + m.metric + '.json');
//                 let outJSON= {};
//                 outJSON["map"] = jsonTransform(r);
//                 if (m.accuracy) {
//                     var a = require('./tmp/m' + m.metric + '-accuracy.json');
//                     outJSON["a"] = jsonTransform(a);
//                 }
//                 fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
//             }
//             if (m.type === "mean") {
//                 var n = require('./tmp/n' + m.metric + '.json');
//                 let outJSON= {};
//                 outJSON["map"] = jsonTransform(n);
//                 if (m.accuracy) {
//                     let a = require('./tmp/m' + m.metric + '-accuracy.json');
//                     outJSON["a"] = jsonTransform(a);
//                 }
//                 fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
//             }
//             if (m.type === "weighted") {
//                 let outJSON= {};
//                 if (m.accuracy) {
//                     var a = require('./tmp/m' + m.metric + '-accuracy.json');
//                     outJSON['a'] = jsonTransform(a);
//                 }
//                 let r = require('./tmp/r' + m.metric + '.json');
//                 let d = require('./tmp/d' + m.metric + '.json');
//                 var jsonArrayR = jsonTransform(r);
//                 var jsonArrayD = jsonTransform(d);
//                 for (key in jsonArrayR) {
//                     for (key2 in jsonArrayR[key]) {
//                         if (isNumeric(jsonArrayR[key][key2]) && isNumeric(jsonArrayD[key][key2])) {
//                             jsonArrayR[key][key2] = Math.round((jsonArrayR[key][key2] / jsonArrayD[key][key2]) * 1000) / 1000;
//                         } else {
//                             jsonArrayR[key][key2] = null;
//                         }
//                     }
//                 }
//                 outJSON["w"] = jsonArrayD;
//                 outJSON["map"] = jsonArrayR;
//                 fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
//             }
//         });
//         del(['./tmp/**']);
//         cb();

//     });

// });

// // markdown
// gulp.task('markdown', ['clean'], function() {
//     return gulp.src('data/meta/*.md')
//         .pipe(markdown())
//         .pipe(gulp.dest('public/data/meta/'));
// });<commit_msg>file clean up<commit_after>////////////////////////////////////////////////
// data processing
////////////////////////////////////////////////

var fs = require('fs');
var path = require('path');
var dataConfig = require('../data/config/data.js');
const csv = require('csvtojson');
const _ = require('lodash');
var dest = "./public/data/metric";

// return true if convertable to number
function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
}

// transform csv2json array to id: {y_2012: value} object format
function jsonTransform(jsonArray) {
    var jsonOut = {};
    for (var i = 0; i < jsonArray.length; i++) {
        jsonOut[jsonArray[i]["id"]] = {};
        for (var key in jsonArray[i]) {
            if (key !== 'id') {
                if (isNumeric(jsonArray[i][key])) {
                    jsonOut[jsonArray[i]["id"]][key] = Number(jsonArray[i][key]);
                } else {
                    jsonOut[jsonArray[i]["id"]][key] = null;
                }
            }
        }
    }
    return jsonOut;
}

// loop through the variables
_.each(dataConfig, function(m) {
    if (m.type === "sum") {
        csv()
            .fromFile('data/metric/r' + m.metric + '.csv')
            .on('end_parsed', (jsonObj)=>{
                let outJSON= {};
                outJSON["map"] = jsonTransform(jsonObj);

                if (m.accuracy) {
                    csv()
                        .fromFile('data/metric/m' + m.metric + '-accuracy.csv')
                        .on('end_parsed', (jsonObj)=>{
                            outJSON["a"] = jsonTransform(jsonObj);
                            fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
                        })
                        .on('done',(error)=>{
                            if (error) console.log(error);
                        });
                } else {
                    fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
                }
            })
            .on('done',(error)=>{
                if (error) console.log(error);
            });
    }
    if (m.type === "mean") {
        csv()
            .fromFile('data/metric/n' + m.metric + '.csv')
            .on('end_parsed', (jsonObj)=>{
                let outJSON= {};
                outJSON["map"] = jsonTransform(jsonObj);

                if (m.accuracy) {
                    csv()
                        .fromFile('data/metric/m' + m.metric + '-accuracy.csv')
                        .on('end_parsed', (jsonObj)=>{
                            outJSON["a"] = jsonTransform(jsonObj);
                            fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
                        })
                        .on('done',(error)=>{
                            if (error) console.log(error);
                        });
                } else {
                    fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
                }
            })
            .on('done',(error)=>{
                if (error) console.log(error);
            });
    }
    if (m.type === "weighted") {
        csv()
            .fromFile('data/metric/r' + m.metric + '.csv')
            .on('end_parsed', (jsonObj)=>{
                let outJSON= {};
                let jsonArrayR = jsonTransform(jsonObj);

                csv()
                    .fromFile('data/metric/d' + m.metric + '.csv')
                    .on('end_parsed', (jsonObj)=>{
                        var jsonArrayD = jsonTransform(jsonObj);
                        for (key in jsonArrayR) {
                            for (key2 in jsonArrayR[key]) {
                                if (isNumeric(jsonArrayR[key][key2]) && isNumeric(jsonArrayD[key][key2])) {
                                    jsonArrayR[key][key2] = Math.round((jsonArrayR[key][key2] / jsonArrayD[key][key2]) * 1000) / 1000;
                                } else {
                                    jsonArrayR[key][key2] = null;
                                }
                            }
                        }
                        outJSON["w"] = jsonArrayD;
                        outJSON["map"] = jsonArrayR;
                        if (m.accuracy) {
                            csv()
                                .fromFile('data/metric/m' + m.metric + '-accuracy.csv')
                                .on('end_parsed', (jsonObj)=>{
                                    outJSON["a"] = jsonTransform(jsonObj);
                                    fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
                                })
                                .on('done',(error)=>{
                                    if (error) console.log(error);
                                });
                        } else {
                            fs.writeFileSync(path.join(dest, `m${m.metric}.json`), JSON.stringify(outJSON, null, '  '));
                        }

                    })
                    .on('done',(error)=>{
                        if (error) console.log(error);
                    });
            })
            .on('done',(error)=>{
                if (error) console.log(error);
            });
    }
});

<|endoftext|>


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

export const CONTEXT_KEY = 'styled_library_themer';
export const contextType = PropTypes.shape({
  variants: PropTypes.arrayOf(PropTypes.string),
});

export default WrappedComponent => {
  return class VariantWrapper extends React.Component {
    static contextTypes = {
      [CONTEXT_KEY]: contextType,
    };

    render() {
      const {
        [CONTEXT_KEY]: { variants } = { variants: ['default'] },
      } = this.context;
      const { children, ...rest } = this.props;
      return (
        <WrappedComponent {...rest} variants={variants} variant={variants}>
          {children}
        </WrappedComponent>
      );
    }
  };
};
<commit_msg>Expose wrapped component from variant connector<commit_after>import React from 'react';
import PropTypes from 'prop-types';

export const CONTEXT_KEY = 'styled_library_themer';
export const contextType = PropTypes.shape({
  variants: PropTypes.arrayOf(PropTypes.string),
});

export default WrappedComponent => {
  return class VariantWrapper extends React.Component {
    static WrappedComponent = WrappedComponent;

    static contextTypes = {
      [CONTEXT_KEY]: contextType,
    };

    render() {
      const {
        [CONTEXT_KEY]: { variants } = { variants: ['default'] },
      } = this.context;
      const { children, ...rest } = this.props;
      return (
        <WrappedComponent {...rest} variants={variants} variant={variants}>
          {children}
        </WrappedComponent>
      );
    }
  };
};
<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import React from 'react';
import Relay from 'react-relay/classic';
import classNames from 'classnames';
import DocumentTitle from 'react-document-title';

import Panel from '../shared/Panel';
import Button from '../shared/Button';
import FormRadioGroup from '../shared/FormRadioGroup';
import { formatNumber } from '../../lib/number';

import BillingCreditCardForm from './BillingCreditCardForm';

class BillingUpgrade extends React.Component {
  state = {
    saving: false
  }

  render() {
    return (
      <DocumentTitle title={`Upgrade · ${this.props.organization.name}`}>
        <form onSubmit={this.handleFormSubmit}>

Upgrade your Subscription

              <Panel>
                <Panel.Section>
                  Choose your plan

                      {this.renderPlan("standard", window._billing["plans"]["standard"])}

                      {this.renderPlan("enterprise", window._billing["plans"]["enterprise"])}

                </Panel.Section>

                <Panel.Section>
                  <FormRadioGroup
                    name="interval"
                    label="How often do you want to be billed?"
                    value={"monthly"}
                    options={[
                      { label: "Monthly", value: "monthly", help: "Pay month-to-month" },
                      { label: "Yearly", value: "yearly", help: "Save and pay for entire year up front", badge: "Save 15%" }
                    ]}
                  />
                </Panel.Section>

                <Panel.Section>
                  Order summary

Standard Plan

Paying month-to-month

$49

12 Users

Each additional user costs $7 each

$84

$133 per month

Your next invoice will be issued on the 19th of July, 2017

                </Panel.Section>

                <BillingCreditCardForm disabled={this.state.saving} onChange={this.handleCreditCardFormChange} />

                <Panel.Footer>
                  <Button loading={this.state.saving && "Upgrading…"} theme="success">Upgrade</Button>
                </Panel.Footer>
              </Panel>

        </form>
      </DocumentTitle>
    );
  }

  renderPlan(id, plan) {
    let price = plan["price"] / 100;
    let features = [];

    features.push(
      {formatNumber(plan.limits["agents"])} connected agents,
      {formatNumber(plan.limits["users"])} included users,
      {plan.limits["builds_per_month"] ? formatNumber(plan.limits["builds_per_month"]) : "Unlimited"} builds
    );

    if (plan.features["custom_retention"]) {
      features.push(
        Customizable retention
      )
    } else {
      features.push(
        {formatNumber(plan.limits["data_retention_days"])} days retention
      )
    }

    features.push(
      SSO
    )

    if (plan.features["chat_support"] && plan.features["priority_support"]) {
      features.push(
        Priority email + live chat support
      )
    } else {
      features.push(
        Priority email support
      )
    }

    features.push(
      Account manager,
      Audit logging,
      99.95% update SLA,
      Invoice payment
    )

    return (

          <input type="radio" name="upgrade[form]" value={id} />

{plan["label"]}

${price} per month

              {features.map((el, idx) =>
{el}
)}

    )
  }

  handleFormSubmit = (event) => {
    event.preventDefault();

    this.setState({ saving: true });
  };

  handleCreditCardFormChange = (field, value) => {
    console.log(field, value);
  };
}

export default Relay.createContainer(BillingUpgrade, {
  fragments: {
    organization: () => Relay.QL`
      fragment on Organization {
        name
        slug
      }
    `
  }
});
<commit_msg>More plumbing in the billing upgrade form<commit_after>import PropTypes from 'prop-types';
import React from 'react';
import Relay from 'react-relay/classic';
import classNames from 'classnames';
import DocumentTitle from 'react-document-title';

import Panel from '../shared/Panel';
import Button from '../shared/Button';
import FormRadioGroup from '../shared/FormRadioGroup';
import { formatNumber } from '../../lib/number';

import BillingCreditCardForm from './BillingCreditCardForm';

class BillingUpgrade extends React.Component {
  state = {
    saving: false,
    plan: "standard",
    interval: "monthly"
  }

  // Internal variable used to store the credit card attributes as we change
  // them.
  creditCard = {};

  render() {
    return (
      <DocumentTitle title={`Upgrade · ${this.props.organization.name}`}>
        <form onSubmit={this.handleFormSubmit}>

Upgrade your Subscription

              <Panel>
                <Panel.Section>
                  Choose your plan

                      {this.renderPlan("standard", window._billing["plans"]["standard"])}

                      {this.renderPlan("enterprise", window._billing["plans"]["enterprise"])}

                </Panel.Section>

                <Panel.Section>
                  <FormRadioGroup
                    name="interval"
                    label="How often do you want to be billed?"
                    value={this.state.interval}
                    onChange={this.handleIntervalChange}
                    options={[
                      { label: "Monthly", value: "monthly", help: "Pay month-to-month" },
                      { label: "Yearly", value: "yearly", help: "Save and pay for entire year up front", badge: "Save 15%" }
                    ]}
                  />
                </Panel.Section>

                <Panel.Section>
                  Order summary

Standard Plan

Paying month-to-month

$49

12 Users

Each additional user costs $7 each

$84

$133 per month

Your next invoice will be issued on the 19th of July, 2017

                </Panel.Section>

                <BillingCreditCardForm disabled={this.state.saving} onChange={this.handleCreditCardFormChange} />

                <Panel.Footer>
                  <Button loading={this.state.saving && "Upgrading…"} theme="success">Upgrade</Button>
                </Panel.Footer>
              </Panel>

        </form>
      </DocumentTitle>
    );
  }

  renderPlan(id, plan) {
    let price = plan["price"] / 100;
    let features = [];

    features.push(
      {formatNumber(plan.limits["agents"])} connected agents,
      {formatNumber(plan.limits["users"])} included users,
      {plan.limits["builds_per_month"] ? formatNumber(plan.limits["builds_per_month"]) : "Unlimited"} builds
    );

    if (plan.features["custom_retention"]) {
      features.push(
        Customizable retention
      )
    } else {
      features.push(
        {formatNumber(plan.limits["data_retention_days"])} days retention
      )
    }

    features.push(
      SSO
    )

    if (plan.features["chat_support"] && plan.features["priority_support"]) {
      features.push(
        Priority email + chat support
      )
    } else {
      features.push(
        Priority email support
      )
    }

    features.push(
      Account manager,
      Audit logging,
      99.95% update SLA,
      Invoice payment
    )

    let selected = (this.state.plan === id);
    let classes = classNames("p3", {
      "bg-silver": selected
    })

    return (

            <input type="radio" value={id} onChange={this.handlePlanChange} checked={selected} />

{plan["label"]}

${price} per month

              {features.map((el, idx) =>
{el}
)}

    )
  }

  handleFormSubmit = (event) => {
    event.preventDefault();

    this.setState({ saving: true });

    console.log(this.state.plan);
    console.log(this.state.interval);
    console.log(this.creditCard);
  };

  handlePlanChange = (event) => {
    this.setState({ plan: event.target.value });
  };

  handleIntervalChange = (event) => {
    this.setState({ interval: event.target.value });
  };

  handleCreditCardFormChange = (field, value) => {
    this.creditCard[field] = value;
  };
}

export default Relay.createContainer(BillingUpgrade, {
  fragments: {
    organization: () => Relay.QL`
      fragment on Organization {
        name
        slug
      }
    `
  }
});
<|endoftext|>


<commit_before>//@flow
import React, { Fragment, type ComponentType } from 'react';
import Card from 'app/components/Card';
import Icon from 'app/components/Icon';
import Flex from 'app/components/Layout/Flex';
import { connect } from 'react-redux';
import { Gallery } from 'app/actions/ActionTypes';
import Tooltip from 'app/components/Tooltip';
import {
  selectGalleryPictureById,
  type UploadStatus,
  type GalleryPictureEntity,
  initialUploadStatus,
} from 'app/reducers/galleryPictures';
import { Image } from 'app/components/Image';

type StateProps = {
  uploadStatus: UploadStatus,
  lastImage: ?GalleryPictureEntity,
};

type DispatchedProps = {
  hideUploadStatus: () => void,
};

type Props = StateProps & DispatchedProps;

const style = {
  zIndex: 2,
  margin: 40,
  position: 'fixed',
  bottom: 0,
  left: 0,
};
const UploadStatusCard = ({
  uploadStatus,
  lastImage,
  hideUploadStatus,
}: Props) => {
  if (!uploadStatus.showStatus) return null;

  const uploadDone =
    uploadStatus.successCount + uploadStatus.failCount ===
    uploadStatus.imageCount;

  const hasFailedUploads = uploadStatus.failCount !== 0;

  return (
    <Card style={style}>

        <Icon
          style={{ cursor: 'pointer' }}
          size={24}
          onClick={hideUploadStatus}
          name="close"
        />

      {uploadDone ? (
        <Fragment>

{uploadStatus.successCount} bilder ble lastet opp

        </Fragment>
      ) : (
        <Fragment>

Laster opp bilder

            Status: {uploadStatus.successCount} av{' '}
            {uploadStatus.imageCount}

        </Fragment>
      )}
      {hasFailedUploads && (
        <Tooltip
          list
          content={
            <Flex column>
              {uploadStatus.failedImages.map((name, index) => (
                // Since we never remove elements from the list, we can use
                // the index as the key,
                <Flex key={index}>{name}</Flex>
              ))}
            </Flex>
          }
        >
          Antall feil: {uploadStatus.failCount}
        </Tooltip>
      )}

      {lastImage && (
        <Image
          alt="Last"
          style={{ width: 250, height: 100, objectFit: 'cover' }}
          src={lastImage.thumbnail}
        />
      )}
    </Card>
  );
};

const mapStateToProps: (any) => StateProps = (state) => {
  const {
    uploadStatus = initialUploadStatus,
  }: { uploadStatus: UploadStatus } = state.galleryPictures;

  const lastImage: ?GalleryPictureEntity = selectGalleryPictureById(state, {
    pictureId: uploadStatus.lastUploadedImage,
  });
  return { uploadStatus, lastImage };
};

const mapDispatchToProps = (dispatch) => ({
  hideUploadStatus: () =>
    dispatch({
      type: Gallery.HIDE_UPLOAD_STATUS,
    }),
});

const ConnectedUploadStatusCard = connect(
  mapStateToProps,
  mapDispatchToProps
)(UploadStatusCard);

export default ConnectedUploadStatusCard;

export const addUploadStatusCard = <T>(Component: ComponentType<T>) => (
  props: T
) =>
  true && (
    <Fragment>
      <Component {...props} />
      <ConnectedUploadStatusCard />
    </Fragment>
  );
<commit_msg>Remove unused (and lint error producing) component<commit_after>//@flow
import React, { Fragment } from 'react';
import Card from 'app/components/Card';
import Icon from 'app/components/Icon';
import Flex from 'app/components/Layout/Flex';
import { connect } from 'react-redux';
import { Gallery } from 'app/actions/ActionTypes';
import Tooltip from 'app/components/Tooltip';
import {
  selectGalleryPictureById,
  type UploadStatus,
  type GalleryPictureEntity,
  initialUploadStatus,
} from 'app/reducers/galleryPictures';
import { Image } from 'app/components/Image';

type StateProps = {
  uploadStatus: UploadStatus,
  lastImage: ?GalleryPictureEntity,
};

type DispatchedProps = {
  hideUploadStatus: () => void,
};

type Props = StateProps & DispatchedProps;

const style = {
  zIndex: 2,
  margin: 40,
  position: 'fixed',
  bottom: 0,
  left: 0,
};
const UploadStatusCard = ({
  uploadStatus,
  lastImage,
  hideUploadStatus,
}: Props) => {
  if (!uploadStatus.showStatus) return null;

  const uploadDone =
    uploadStatus.successCount + uploadStatus.failCount ===
    uploadStatus.imageCount;

  const hasFailedUploads = uploadStatus.failCount !== 0;

  return (
    <Card style={style}>

        <Icon
          style={{ cursor: 'pointer' }}
          size={24}
          onClick={hideUploadStatus}
          name="close"
        />

      {uploadDone ? (
        <Fragment>

{uploadStatus.successCount} bilder ble lastet opp

        </Fragment>
      ) : (
        <Fragment>

Laster opp bilder

            Status: {uploadStatus.successCount} av{' '}
            {uploadStatus.imageCount}

        </Fragment>
      )}
      {hasFailedUploads && (
        <Tooltip
          list
          content={
            <Flex column>
              {uploadStatus.failedImages.map((name, index) => (
                // Since we never remove elements from the list, we can use
                // the index as the key,
                <Flex key={index}>{name}</Flex>
              ))}
            </Flex>
          }
        >
          Antall feil: {uploadStatus.failCount}
        </Tooltip>
      )}

      {lastImage && (
        <Image
          alt="Last"
          style={{ width: 250, height: 100, objectFit: 'cover' }}
          src={lastImage.thumbnail}
        />
      )}
    </Card>
  );
};

const mapStateToProps: (any) => StateProps = (state) => {
  const {
    uploadStatus = initialUploadStatus,
  }: { uploadStatus: UploadStatus } = state.galleryPictures;

  const lastImage: ?GalleryPictureEntity = selectGalleryPictureById(state, {
    pictureId: uploadStatus.lastUploadedImage,
  });
  return { uploadStatus, lastImage };
};

const mapDispatchToProps = (dispatch) => ({
  hideUploadStatus: () =>
    dispatch({
      type: Gallery.HIDE_UPLOAD_STATUS,
    }),
});

const ConnectedUploadStatusCard = connect(
  mapStateToProps,
  mapDispatchToProps
)(UploadStatusCard);

export default ConnectedUploadStatusCard;
<|endoftext|>