<commit_before>var FS = require('fs');
var GM = require('gm');
var Fabric = require('fabric').fabric;
var Cloner = require('cloneextend');
var argv = require('optimist').argv;

//Values obtained from contemporary image markup dialog, 2013-02-18
var colorValues = {
  'red': '#C73D23',
  'orange': '#FF9B3B',
  'yellow': '#F5E327',
  'green': '#2EDF8F',
  'blue': '#3856EA',
  'violet': '#E065BF',
  'black': '#191919'
};

function usage(err) {
  console.log('Example Usage:');
  console.log('node imagemarkup.js [--help|-h] - Show this information');
  console.log('node imagemarkup.js --input infile.jpg --output outfile.jpg --markup \'[markup_string]\'');
  console.log('node imagemarkup.js --json \'[json_string]\'');
  //TODO: "See README file for specification"
  if (err)
    process.exit(err);
  else
    process.exit(0);
}

function processArgs() {
  if (argv.help || argv.h) {
    usage();
  }

  var json;
  if (argv.json && argv.markup) {
    console.error('Invalid usage.');
    usage(-1);
  } else if (argv.json) {
    json = JSON.parse(argv.json);
    cleanJSON(json);
    processImage(json);
  } else if (argv.markup) {
    if (!argv.input || !argv.output) {
      console.error('Invalid usage. Input or output path missing.');
      usage(-1);
    }
    convertMarkupToJSON(argv.markup, argv.input, argv.output);
  } else {
    console.error('Invalid uage.');
    usage(-1);
  }
}

function validateJSON(json, level) {
  String.prototype.repeat = function (num) {
    return new Array(num+1).join(this);
  }
  if (!level) {
    console.log("{");
    validateJSON(json, 1);
    console.log("}");
  } else {
    for (property in json) {
      console.log("\t".repeat(level) + property + ": " + json[property] + " [" + typeof(json[property]) + "]");
      if (typeof(json[property]) == 'object') {
        console.log("\t".repeat(level) + "{");
        validateJSON(json[property], level+1);
        console.log("\t".repeat(level) + "}");
      }
    }
  }
}

/**
 * Cycles through an object and changes all numeric fields to ints
 * where necessary.
 */
function cleanJSON(json) {
  for (property in json) {

    if (typeof(json[property]) == 'object') {
      cleanJSON(json[property]);
    }
    else if (property == 'x' || property == 'y' ||
             property == 'width' || property == 'height' ||
             property == 'radius') {
      if (typeof(json[property]) == 'string') {
        json[property] = parseInt(json[property]);
      }
    }
  }
}

function convertMarkupToJSON(markup, infile, outfile) {
  var json = {};

  GM(infile).size(function (err, size) {
    if (err) throw err;

    json['dimensions'] = size;
    json['finalDimensions'] = size;

    json['instructions'] = {};

    var instructions = markup.split(";");
    for (var i = 0; i < instructions.length; ++i) {
      if (instructions[i] == '') continue;

      var args = instructions[i].split(",");
      var command = args[0];
      switch (command) {
        case 'crop':
          var position = args[1].split("x");
          position[0] = parseInt(position[0]);
          position[1] = parseInt(position[1]);
          var from = {
            'x': position[0],
            'y': position[1]
          };

          var dimensions = args[2].split("x");
          dimensions[0] = parseInt(dimensions[0]);
          dimensions[1] = parseInt(dimensions[1]);
          var size = {
            'width': dimensions[0],
            'height': dimensions[1]
          };

          var crop = {};
          crop['from'] = from;
          crop['size'] = size;

          json['instructions']['crop'] = crop;
          json['finalDimensions'] = crop['size'];
          break;
        case 'circle':
          if (!json['instructions']['draw']) json['instructions']['draw'] = new Array();

          var position = args[1].split("x");
          position[0] = parseInt(position[0]);
          position[1] = parseInt(position[1]);
          var from = {
            'x': position[0],
            'y': position[1]
          };

          var radius = parseInt(args[2]);
          var color = args[3];

          var circle = {};
          circle['from'] = from;
          circle['radius'] = radius;
          circle['color'] = color;

          json['instructions']['draw'].push({'circle': circle});
          break;
        case 'rectangle':
          if (!json['instructions']['draw']) json['instructions']['draw'] = new Array();

          var position = args[1].split("x");
          position[0] = parseInt(position[0]);
          position[1] = parseInt(position[1]);
          var from = {
            'x': position[0],
            'y': position[1]
          };

          var dimensions = args[2].split("x");
          dimensions[0] = parseInt(dimensions[0]);
          dimensions[1] = parseInt(dimensions[1]);
          var size = {
            'width': dimensions[0],
            'height': dimensions[1]
          };

          var color = args[3];

          var rectangle = {
            'from': from,
            'size': size,
            'color': color
          };

          json['instructions']['draw'].push({'rectangle': rectangle});
          break;
        default:
      }
    }

    json['sourceFile'] = infile;
    json['destinationFile'] = outfile;

    processImage(json);
  });
}

function processImage(json) {
  var canvas = Fabric.createCanvasForNode(json['finalDimensions']['width'],json['finalDimensions']['height']);

  var imagePath = json['sourceFile'];

  var crop = json['instructions']['crop'];
  var imageOffset = crop != "undefined" ?
   {'x':crop['from']['x'],
    'y':crop['from']['y']} :
   {'x':0,'y':0};

  function applyBackground(canvas) {
    FS.readFile(imagePath, function (err, blob) {
      if (err) throw err;

      var dimensions = json['dimensions'];
      var finalDimensions = json['finalDimensions'];
      img = {'width': dimensions['width'], 'height': dimensions['height'], 'src':blob};

      Fabric.Image.fromObject(img, function(fimg) {
        top = img.height/2 - imageOffset['y'];
        if (top % 1 != 0) {
          top -= 0.5;
        }
        left = img.width / 2 - imageOffset['x'];
        if (left % 1 != 0) {
          left -= 0.5;
        }

        canvas.add(fimg.set('top', top).set('left', left));

        applyMarkup(canvas);
      });
    });
  }

  function applyMarkup(canvas) {
    var size = json['dimensions'];

    for (instruction in json['instructions']) {
      switch (instruction) {
        case 'draw':
          json['instructions']['draw'].forEach(function (e) {
            for (shapeName in e) {
              switch (shapeName) {
                case 'rectangle':
                  shape = e[shapeName];
                  drawRectangle(json, canvas, shape, imageOffset);
                  break;
                case 'circle':
                  shape = e[shapeName];
                  drawCircle(json, canvas,shape, imageOffset);
                  break;
                default:
                  console.error('Unsupported Shape: ' + shapeName);
              }
            }

            writeCanvas(canvas);
          });
          break;
        case 'crop':
          //もう処理していたから無視する
          break;
        default:
          console.error('Unsupported Instruction: ' + instruction);
      }
    }
  }

  function writeCanvas(canvas) {
    var outstream = FS.createWriteStream(json['destinationFile']),
        stream = canvas.createJPEGStream({
          quality: 93
        });

    stream.on('data', function(chunk) {
      outstream.write(chunk);
    });
  }

  applyBackground(canvas);
}

function drawRectangle(json, canvas, shape, imageOffset) {
  shape['stroke'] = Math.max(Math.round(json['finalDimensions']['width'] / 300 * 2), 2);

  var rect = {
    left: shape['from']['x']-imageOffset['x'],
    top: shape['from']['y']-imageOffset['y'],
    width: shape['size']['width'],
    height: shape['size']['height'],
    strokeWidth: shape['stroke'],
    stroke: colorValues[shape['color']],
    fill: 'transparent'
  }

  //Fabric調整
  rect['top'] = rect['top'] + rect['height'] / 2 + rect['strokeWidth'] / 2;
  rect['left'] = rect['left'] + rect['width'] / 2 + rect['strokeWidth'] / 2;

  canvas.add(new Fabric.Rect(rect));
}

function drawCircle(json, canvas, shape, imageOffset) {
  shape['stroke'] = Math.max(Math.round(shape['radius'] / 4), 5);

  var circle = {
    left: shape['from']['x']-imageOffset['x'],
    top: shape['from']['y']-imageOffset['y'],
    radius: shape['radius'],
    strokeWidth: shape['stroke'],
    stroke: colorValues[shape['color']],
    fill: 'transparent'
  };
  var circleBorder = Cloner.clone(circle);
  circleBorder['radius'] += 1;
  circleBorder['stroke'] = 'white';
  var circleShadow = Cloner.clone(circle);
  circleShadow['left'] += 10;
  circleShadow['top'] += 10;
  circleShadow['stroke'] = 'rgba(0,0,0,0.5)';

  canvas.add(new Fabric.Circle(circleShadow));
  canvas.add(new Fabric.Circle(circle));
  canvas.add(new Fabric.Circle(circleBorder));
}

processArgs();
<commit_msg>Tweak circle outline<commit_after>var FS = require('fs');
var GM = require('gm');
var Fabric = require('fabric').fabric;
var Cloner = require('cloneextend');
var argv = require('optimist').argv;

//Values obtained from contemporary image markup dialog, 2013-02-18
var colorValues = {
  'red': '#C73D23',
  'orange': '#FF9B3B',
  'yellow': '#F5E327',
  'green': '#2EDF8F',
  'blue': '#3856EA',
  'violet': '#E065BF',
  'black': '#191919'
};

function usage(err) {
  console.log('Example Usage:');
  console.log('node imagemarkup.js [--help|-h] - Show this information');
  console.log('node imagemarkup.js --input infile.jpg --output outfile.jpg --markup \'[markup_string]\'');
  console.log('node imagemarkup.js --json \'[json_string]\'');
  //TODO: "See README file for specification"
  if (err)
    process.exit(err);
  else
    process.exit(0);
}

function processArgs() {
  if (argv.help || argv.h) {
    usage();
  }

  var json;
  if (argv.json && argv.markup) {
    console.error('Invalid usage.');
    usage(-1);
  } else if (argv.json) {
    json = JSON.parse(argv.json);
    cleanJSON(json);
    processImage(json);
  } else if (argv.markup) {
    if (!argv.input || !argv.output) {
      console.error('Invalid usage. Input or output path missing.');
      usage(-1);
    }
    convertMarkupToJSON(argv.markup, argv.input, argv.output);
  } else {
    console.error('Invalid uage.');
    usage(-1);
  }
}

function validateJSON(json, level) {
  String.prototype.repeat = function (num) {
    return new Array(num+1).join(this);
  }
  if (!level) {
    console.log("{");
    validateJSON(json, 1);
    console.log("}");
  } else {
    for (property in json) {
      console.log("\t".repeat(level) + property + ": " + json[property] + " [" + typeof(json[property]) + "]");
      if (typeof(json[property]) == 'object') {
        console.log("\t".repeat(level) + "{");
        validateJSON(json[property], level+1);
        console.log("\t".repeat(level) + "}");
      }
    }
  }
}

/**
 * Cycles through an object and changes all numeric fields to ints
 * where necessary.
 */
function cleanJSON(json) {
  for (property in json) {

    if (typeof(json[property]) == 'object') {
      cleanJSON(json[property]);
    }
    else if (property == 'x' || property == 'y' ||
             property == 'width' || property == 'height' ||
             property == 'radius') {
      if (typeof(json[property]) == 'string') {
        json[property] = parseInt(json[property]);
      }
    }
  }
}

function convertMarkupToJSON(markup, infile, outfile) {
  var json = {};

  GM(infile).size(function (err, size) {
    if (err) throw err;

    json['dimensions'] = size;
    json['finalDimensions'] = size;

    json['instructions'] = {};

    var instructions = markup.split(";");
    for (var i = 0; i < instructions.length; ++i) {
      if (instructions[i] == '') continue;

      var args = instructions[i].split(",");
      var command = args[0];
      switch (command) {
        case 'crop':
          var position = args[1].split("x");
          position[0] = parseInt(position[0]);
          position[1] = parseInt(position[1]);
          var from = {
            'x': position[0],
            'y': position[1]
          };

          var dimensions = args[2].split("x");
          dimensions[0] = parseInt(dimensions[0]);
          dimensions[1] = parseInt(dimensions[1]);
          var size = {
            'width': dimensions[0],
            'height': dimensions[1]
          };

          var crop = {};
          crop['from'] = from;
          crop['size'] = size;

          json['instructions']['crop'] = crop;
          json['finalDimensions'] = crop['size'];
          break;
        case 'circle':
          if (!json['instructions']['draw']) json['instructions']['draw'] = new Array();

          var position = args[1].split("x");
          position[0] = parseInt(position[0]);
          position[1] = parseInt(position[1]);
          var from = {
            'x': position[0],
            'y': position[1]
          };

          var radius = parseInt(args[2]);
          var color = args[3];

          var circle = {};
          circle['from'] = from;
          circle['radius'] = radius;
          circle['color'] = color;

          json['instructions']['draw'].push({'circle': circle});
          break;
        case 'rectangle':
          if (!json['instructions']['draw']) json['instructions']['draw'] = new Array();

          var position = args[1].split("x");
          position[0] = parseInt(position[0]);
          position[1] = parseInt(position[1]);
          var from = {
            'x': position[0],
            'y': position[1]
          };

          var dimensions = args[2].split("x");
          dimensions[0] = parseInt(dimensions[0]);
          dimensions[1] = parseInt(dimensions[1]);
          var size = {
            'width': dimensions[0],
            'height': dimensions[1]
          };

          var color = args[3];

          var rectangle = {
            'from': from,
            'size': size,
            'color': color
          };

          json['instructions']['draw'].push({'rectangle': rectangle});
          break;
        default:
      }
    }

    json['sourceFile'] = infile;
    json['destinationFile'] = outfile;

    processImage(json);
  });
}

function processImage(json) {
  var canvas = Fabric.createCanvasForNode(json['finalDimensions']['width'],json['finalDimensions']['height']);

  var imagePath = json['sourceFile'];

  var crop = json['instructions']['crop'];
  var imageOffset = crop != "undefined" ?
   {'x':crop['from']['x'],
    'y':crop['from']['y']} :
   {'x':0,'y':0};

  function applyBackground(canvas) {
    FS.readFile(imagePath, function (err, blob) {
      if (err) throw err;

      var dimensions = json['dimensions'];
      var finalDimensions = json['finalDimensions'];
      img = {'width': dimensions['width'], 'height': dimensions['height'], 'src':blob};

      Fabric.Image.fromObject(img, function(fimg) {
        top = img.height/2 - imageOffset['y'];
        if (top % 1 != 0) {
          top -= 0.5;
        }
        left = img.width / 2 - imageOffset['x'];
        if (left % 1 != 0) {
          left -= 0.5;
        }

        canvas.add(fimg.set('top', top).set('left', left));

        applyMarkup(canvas);
      });
    });
  }

  function applyMarkup(canvas) {
    var size = json['dimensions'];

    for (instruction in json['instructions']) {
      switch (instruction) {
        case 'draw':
          json['instructions']['draw'].forEach(function (e) {
            for (shapeName in e) {
              switch (shapeName) {
                case 'rectangle':
                  shape = e[shapeName];
                  drawRectangle(json, canvas, shape, imageOffset);
                  break;
                case 'circle':
                  shape = e[shapeName];
                  drawCircle(json, canvas,shape, imageOffset);
                  break;
                default:
                  console.error('Unsupported Shape: ' + shapeName);
              }
            }

            writeCanvas(canvas);
          });
          break;
        case 'crop':
          //もう処理していたから無視する
          break;
        default:
          console.error('Unsupported Instruction: ' + instruction);
      }
    }
  }

  function writeCanvas(canvas) {
    var outstream = FS.createWriteStream(json['destinationFile']),
        stream = canvas.createJPEGStream({
          quality: 93
        });

    stream.on('data', function(chunk) {
      outstream.write(chunk);
    });
  }

  applyBackground(canvas);
}

function drawRectangle(json, canvas, shape, imageOffset) {
  shape['stroke'] = Math.max(Math.round(json['finalDimensions']['width'] / 300 * 2), 2);

  var rect = {
    left: shape['from']['x']-imageOffset['x'],
    top: shape['from']['y']-imageOffset['y'],
    width: shape['size']['width'],
    height: shape['size']['height'],
    strokeWidth: shape['stroke'],
    stroke: colorValues[shape['color']],
    fill: 'transparent'
  }

  //Fabric調整
  rect['top'] = rect['top'] + rect['height'] / 2 + rect['strokeWidth'] / 2;
  rect['left'] = rect['left'] + rect['width'] / 2 + rect['strokeWidth'] / 2;

  canvas.add(new Fabric.Rect(rect));
}

function drawCircle(json, canvas, shape, imageOffset) {
  shape['stroke'] = Math.max(Math.round(shape['radius'] / 4), 5);
  whiteStroke = 1;

  var circle = {
    left: shape['from']['x']-imageOffset['x'],
    top: shape['from']['y']-imageOffset['y'],
    radius: shape['radius'],
    strokeWidth: shape['stroke'],
    stroke: colorValues[shape['color']],
    fill: 'transparent'
  };
  var circleBorder = Cloner.clone(circle);
  circleBorder['radius'] = circle['radius'] + circle['strokeWidth'] / 2;
  circleBorder['strokeWidth'] = whiteStroke;
  circleBorder['stroke'] = 'white';
  var circleShadow = Cloner.clone(circle);
  circleShadow['left'] += 10;
  circleShadow['top'] += 10;
  circleShadow['stroke'] = 'rgba(0,0,0,0.5)';

  canvas.add(new Fabric.Circle(circleShadow));
  canvas.add(new Fabric.Circle(circleBorder));
  canvas.add(new Fabric.Circle(circle));
}

processArgs();
<|endoftext|>


<commit_before>Ext.define('Starter.view.user.Form', {
	extend: 'Ext.form.Panel',
	requires: [ 'Ext.form.field.ComboBox', 'Ext.form.field.Tag' ],
	defaultFocus: 'textfield[name=email]',

	reference: 'editPanel',

	cls: 'shadow',
	defaultType: 'textfield',
	defaults: {
		anchor: '50%'
	},
	bodyPadding: 20,

	modelValidation: true,

	items: [ {
		bind: '{selectedUser.email}',
		name: 'email',
		fieldLabel: i18n.user_email
	}, {
		bind: '{selectedUser.firstName}',
		name: 'firstName',
		fieldLabel: i18n.user_firstname
	}, {
		bind: '{selectedUser.lastName}',
		name: 'lastName',
		fieldLabel: i18n.user_lastname
	}, {
		xtype: 'combobox',
		fieldLabel: i18n.language,
		bind: {
			value: '{selectedUser.locale}'
		},
		name: 'locale',
		store: 'languages',
		valueField: 'value',
		queryMode: 'local',
		emptyText: i18n.language_select,
		forceSelection: true,
		editable: false,
		listeners: {
			change: 'onLanguageChange'
		}
	}, {
		bind: '{selectedUser.enabled}',
		fieldLabel: i18n.user_enabled,
		name: 'enabled',
		xtype: 'checkboxfield',
		msgTarget: 'side',
		inputValue: 'true',
		uncheckedValue: 'false'
	}, {
		xtype: 'tagfield',
		fieldLabel: i18n.user_authorities,
		bind: {
			store: '{authorities}',
			value: '{selectedUser.authorities}'
		},
		name: 'authorities',
		displayField: 'name',
		valueField: 'name',
		queryMode: 'local',
		forceSelection: true,
		autoSelect: true,
		delimiter: ',',
		editable: false,
		selectOnFocus: false
	} ],

	dockedItems: [ {
		xtype: 'toolbar',
		dock: 'top',
		items: [ {
			text: 'Users',
			handler: 'back',
			iconCls: 'x-fa fa-arrow-left'
		}, '-', {
			text: i18n.destroy,
			iconCls: 'x-fa fa-trash-o',
			handler: 'erase',
			ui: 'soft-red',
			bind: {
				hidden: '{newUser}'
			}
		}, {
			text: Starter.Util.underline(i18n.save, 'S'),
			accessKey: 's',
			ui: 'soft-green',
			iconCls: 'x-fa fa-floppy-o',
			formBind: true,
			handler: 'save'
		}, '-', {
			text: i18n.user_send_pwresetreq,
			iconCls: 'x-fa fa-envelope-o',
			handler: 'sendPwResetReq',
			bind: {
				hidden: '{newUser}'
			}
		}, {
			text: i18n.user_switchto,
			iconCls: 'x-fa fa-user-secret',
			handler: 'switchTo',
			bind: {
				hidden: '{newUser}'
			}
		}, {
			text: i18n.user_unlock,
			handler: 'unlock',
			iconCls: 'x-fa fa-unlock',
			bind: {
				hidden: '{!selectedUser.lockedOutUntil}'
			}
		}, {
			text: i18n.user_disable_twofactorauth,
			iconCls: 'x-fa fa-trash-o',
			handler: 'disableTwoFactorAuth',
			bind: {
				hidden: '{!selectedUser.twoFactorAuth}'
			}
		} ]
	} ]

});<commit_msg>delimiter is ',' by default. No need to specify it<commit_after>Ext.define('Starter.view.user.Form', {
	extend: 'Ext.form.Panel',
	requires: [ 'Ext.form.field.ComboBox', 'Ext.form.field.Tag' ],
	defaultFocus: 'textfield[name=email]',

	reference: 'editPanel',

	cls: 'shadow',
	defaultType: 'textfield',
	defaults: {
		anchor: '50%'
	},
	bodyPadding: 20,

	modelValidation: true,

	items: [ {
		bind: '{selectedUser.email}',
		name: 'email',
		fieldLabel: i18n.user_email
	}, {
		bind: '{selectedUser.firstName}',
		name: 'firstName',
		fieldLabel: i18n.user_firstname
	}, {
		bind: '{selectedUser.lastName}',
		name: 'lastName',
		fieldLabel: i18n.user_lastname
	}, {
		xtype: 'combobox',
		fieldLabel: i18n.language,
		bind: {
			value: '{selectedUser.locale}'
		},
		name: 'locale',
		store: 'languages',
		valueField: 'value',
		queryMode: 'local',
		emptyText: i18n.language_select,
		forceSelection: true,
		editable: false,
		listeners: {
			change: 'onLanguageChange'
		}
	}, {
		bind: '{selectedUser.enabled}',
		fieldLabel: i18n.user_enabled,
		name: 'enabled',
		xtype: 'checkboxfield',
		msgTarget: 'side',
		inputValue: 'true',
		uncheckedValue: 'false'
	}, {
		xtype: 'tagfield',
		fieldLabel: i18n.user_authorities,
		bind: {
			store: '{authorities}',
			value: '{selectedUser.authorities}'
		},
		name: 'authorities',
		displayField: 'name',
		valueField: 'name',
		queryMode: 'local',
		forceSelection: true,
		autoSelect: true,
		editable: false,
		selectOnFocus: false
	} ],

	dockedItems: [ {
		xtype: 'toolbar',
		dock: 'top',
		items: [ {
			text: 'Users',
			handler: 'back',
			iconCls: 'x-fa fa-arrow-left'
		}, '-', {
			text: i18n.destroy,
			iconCls: 'x-fa fa-trash-o',
			handler: 'erase',
			ui: 'soft-red',
			bind: {
				hidden: '{newUser}'
			}
		}, {
			text: Starter.Util.underline(i18n.save, 'S'),
			accessKey: 's',
			ui: 'soft-green',
			iconCls: 'x-fa fa-floppy-o',
			formBind: true,
			handler: 'save'
		}, '-', {
			text: i18n.user_send_pwresetreq,
			iconCls: 'x-fa fa-envelope-o',
			handler: 'sendPwResetReq',
			bind: {
				hidden: '{newUser}'
			}
		}, {
			text: i18n.user_switchto,
			iconCls: 'x-fa fa-user-secret',
			handler: 'switchTo',
			bind: {
				hidden: '{newUser}'
			}
		}, {
			text: i18n.user_unlock,
			handler: 'unlock',
			iconCls: 'x-fa fa-unlock',
			bind: {
				hidden: '{!selectedUser.lockedOutUntil}'
			}
		}, {
			text: i18n.user_disable_twofactorauth,
			iconCls: 'x-fa fa-trash-o',
			handler: 'disableTwoFactorAuth',
			bind: {
				hidden: '{!selectedUser.twoFactorAuth}'
			}
		} ]
	} ]

});<|endoftext|>


<commit_before>var leds = require('./24x6');
var spectrum = require('./cpp-src/build/Release/spectrum');
var r = require('./vizs/rainbow.js');
var t = require('./vizs/text.js');
var im = require('./vizs/image.js');
var skulls = require('./vizs/skulls.js');
var plasma = require('./vizs/plasma.js');
var fire = require('./vizs/fire.js');
var equalizer = require('./vizs/equalizer.js');
var FRAME_RATE = 30;

var pixels = new Array();
for (var x = 0; x < 24;++x){
  pixels[x] = new Array();
  for (var y = 0; y < 6; y++){
    pixels[x][y] = new Array();
    for (var b = 0; b < 3; b++){
      pixels[x][y][b] = 0;
    }
  }
}

var providers = {
  'rainbow': new r(),
  'text': new t("Dj Polly!"),
  'image': new im(),
  'skulls': new skulls(),
  'fire': new fire(),
  'equalizer': new equalizer(),
  'plasma': new plasma()
};

function go() {
  var d = (new Date).getTime();
  var s;
  try {
    s = spectrum.getSpectrum();
  } catch (x){
    console.log("f: ");
  }
  if (s==undefined){
    console.log("x:");
    s=[0,0,0,0,0,0];
  }
  var volume = (s[0]+s[1]+s[2]+s[3]+s[4]+s[5]+s[6])/7;

//  var v = providers['rainbow'].getFrame(s,volume);
//  var v = providers['text'].getFrame(s,volume);
//  var v = providers['image'].getFrame(s,volume);
//  var v = providers['skulls'].getFrame(s,volume);
//  var v = providers['plasma'].getFrame(s,volume);

  for (var x = 0; x < 24;++x){
    for (var y = 0; y < 6; y++){
      for (var b = 0; b < 3; b++){
        pixels[x][y][b] = 0;
      }
    }
  }
//  var things = ['skulls','plasma','text','rainbow'];
  var things = ['equalizer'];//'fire','text','rainbow','plasma'];

  for (var i = 0; i < things.length; ++i){
    var v = providers[things[i]].getFrame(s,volume);
    for (var x = 0; x < 24;++x){
      for (var y = 0; y < 6;++y){
        for (var b = 0; b < 3; ++b){
          pixels[x][y][b] += v[x][y][b]/things.length;
        }
      }
    }
  }

  for (var x = 0; x < 24;++x){
    for (var y = 0; y < 6;++y){
      leds.setLed(x,y,pixels[x][y][0],pixels[x][y][1],pixels[x][y][2]);
//      leds.setLed(x,y,v[x][y][0],v[x][y][1],v[x][y][2]);
    }
  }
  leds.draw();
  d = (new Date).getTime() - d;
  setTimeout(go,(1000/FRAME_RATE)-d);
  global.gc();
}

go();
<commit_msg>Add glasses to core<commit_after>var leds = require('./24x6');
var spectrum = require('./cpp-src/build/Release/spectrum');
var r = require('./vizs/rainbow.js');
var t = require('./vizs/text.js');
var im = require('./vizs/image.js');
var skulls = require('./vizs/skulls.js');
var plasma = require('./vizs/plasma.js');
var fire = require('./vizs/fire.js');
var equalizer = require('./vizs/equalizer.js');
var glasses = require('./vizs/glasses.js');
var FRAME_RATE = 30;

var pixels = new Array();
for (var x = 0; x < 24;++x){
  pixels[x] = new Array();
  for (var y = 0; y < 6; y++){
    pixels[x][y] = new Array();
    for (var b = 0; b < 3; b++){
      pixels[x][y][b] = 0;
    }
  }
}

var providers = {
  'rainbow': new r(),
  'text': new t("Dj Polly!"),
  'image': new im(),
  'skulls': new skulls(),
  'fire': new fire(),
  'equalizer': new equalizer(),
  'plasma': new plasma(),
  'glasses': new glasses()
};

function go() {
  var d = (new Date).getTime();
  var s;
  try {
    s = spectrum.getSpectrum();
  } catch (x){
    console.log("f: ");
  }
  if (s==undefined){
    console.log("x:");
    s=[0,0,0,0,0,0];
  }
  var volume = (s[0]+s[1]+s[2]+s[3]+s[4]+s[5]+s[6])/7;

//  var v = providers['rainbow'].getFrame(s,volume);
//  var v = providers['text'].getFrame(s,volume);
//  var v = providers['image'].getFrame(s,volume);
//  var v = providers['skulls'].getFrame(s,volume);
//  var v = providers['plasma'].getFrame(s,volume);

  for (var x = 0; x < 24;++x){
    for (var y = 0; y < 6; y++){
      for (var b = 0; b < 3; b++){
        pixels[x][y][b] = 0;
      }
    }
  }
//  var things = ['skulls','plasma','text','rainbow'];
  var things =
['equalizer','glasses'];//'fire','text','rainbow','plasma'];

  for (var i = 0; i < things.length; ++i){
    var v = providers[things[i]].getFrame(s,volume,s[8] > 0);
    for (var x = 0; x < 24;++x){
      for (var y = 0; y < 6;++y){
        for (var b = 0; b < 3; ++b){
          pixels[x][y][b] += v[x][y][b]/things.length;
        }
      }
    }
  }

  for (var x = 0; x < 24;++x){
    for (var y = 0; y < 6;++y){
      leds.setLed(x,y,pixels[x][y][0],pixels[x][y][1],pixels[x][y][2]);
//      leds.setLed(x,y,v[x][y][0],v[x][y][1],v[x][y][2]);
    }
  }
  leds.draw();
  d = (new Date).getTime() - d;
  setTimeout(go,(1000/FRAME_RATE)-d);
  global.gc();
}

go();
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010 Nils Schneider
 * Distributed under the MIT/X11 software license, see the accompanying
 * file license.txt or http://www.opensource.org/licenses/mit-license.php.
 */

/* settings:
 * {
 *  generateConfirm: 120
 * }
 */
function TXList(list, app, settings) {
	this.sortTX = function(a, b) {
		if(a.time != b.time)
			return (a.time - b.time);

		if(a.category != b.category)
			return (b.category < a.category) ? -1 : 1;

		return (b.amount - a.amount);
	}

	this.clear = function() {
		list.children().remove();
	}

	this.processRPC = function(transactions, error) {
		if (error)
			return;

		var start = new Date().getTime();

		var transactions = jQuery.grep(transactions,
				function(n, i) {
					return n.account == app.bitcoin.settings.account;
				});

		transactions.sort(this.sortTX);

		list.children('#txlistempty').remove();

		if (transactions.length == 0)
			list.append('
no transactions
');

		for (var key in transactions)
			this.processTX(transactions[key]);

		list.children('tr:not(.txinfo):odd').addClass('odd').next('.txinfo').addClass('odd');
		list.children('tr:not(.txinfo):even').removeClass('odd').next('.txinfo').removeClass('odd');

		/* adjust refresh interval of app depending processing time of txlist */
		var end = new Date().getTime();
		var time = end - start;
		app.setRefreshInterval(time * 10);
	}

	this.processTX = function(tx) {
		if (tx.time == undefined)
			tx.time = 0;

		if (tx.txid == undefined)
			tx.txid = (tx.time + tx.amount + tx.otheraccount).replace(/ /g,'');

		tx.txid += tx.category;

		var txrow = $(document.getElementById(tx.txid));

		if (txrow.length == 0) {
			txrow = $('

');
			list.prepend(txrow);
			var txdiv = $('

');
			txrow.after(txdiv);

			txrow.click( function() {
					var div = $(this).next('tr.txinfo').children('td').children('div');
					if (app.useSlide) div.slideToggle('fast');
					else div.toggle();
				});
		}

		var checksum = tx.txid + tx.confirmations + tx.time;

		/* Only update TX if it differs from current one */
		if(txrow.attr('checksum') != checksum) {
			txrow.attr('checksum', checksum);
			txrow.html(this.renderRow(tx));

			txrow.next('tr.txinfo').children('td').children('div').html(this.renderInfo(tx));

			if (tx.confirmations == 0 || (tx.category == "generate" && tx.confirmations < settings.generateConfirm))
				txrow.addClass("unconfirmed");
			else
				txrow.removeClass("unconfirmed");
		}
	}

	this.renderInfo = function(tx) {
		var html = "";
		var extra = "";

		switch (tx.category) {
			case "generate":
				html += "Generated coins
";
				break;
			case "move":
				html += "Moved " + (tx.amount<0?"to":"from") + ": " + tx.otheraccount.prettyAccount() + "
";
				break;
			case "send":
				if (tx.to)
					extra = " (" + tx.to + ")";
				html += "Sent to: " + tx.address + extra + "
";
				break;
			case "receive":
				if (tx.from)
					extra = " (" + tx.from + ")";
				html += "Received on: " + tx.address + extra + "
";
				break;
			default:
				html += "Category: " + tx.category + "
";
		}

		if(tx.confirmations != undefined) html += "Confirmations: " + tx.confirmations + "
";
		if(tx.fee != undefined) html += "Fee: " + tx.fee.formatBTC() + "
";
		if(tx.comment != "" && tx.comment != undefined) html += "Comment: " + tx.comment + "
";

		return html;
	}

	this.renderRow = function(tx) {
		var confirmations = tx.confirmations<10?tx.confirmations:'✓';

		if (tx.category == "generate")
			confirmations = tx.confirmations<settings.generateConfirm?'&#x2717':'&#x2713';

		var timestamp = new Date();
		timestamp.setTime (tx.time * 1000);

		var info = tx.category.capitalize();

		if (tx.category == 'send')
			if (tx.to)
				info = tx.to;
			else
				info = tx.address;

		if (tx.category == 'receive')
			if (tx.from)
				info = tx.from;
			else
				info = tx.address;

		if (tx.comment)
			info += " (" + tx.comment + ")";

		if (tx.category == 'move')
			info = (tx.amount<0?"to ":"from ") + tx.otheraccount.prettyAccount();

		var amountClass = (tx.amount<0?'debit':'credit');

		var html = '' + confirmations + '	';
		html += '' + timestamp.format(app.dateFormat) + '	';
		html += '' + info + '	';
		html += '' + tx.amount.formatBTC(true) + '	';

		return html;
	}

	this.refresh = function() {
		app.bitcoin.listTransactions(jQuery.proxy(this, 'processRPC'));
	}
}
<commit_msg>get size of existing txlist, measure time<commit_after>/*
 * Copyright (c) 2010 Nils Schneider
 * Distributed under the MIT/X11 software license, see the accompanying
 * file license.txt or http://www.opensource.org/licenses/mit-license.php.
 */

/* settings:
 * {
 *  generateConfirm: 120
 * }
 */
function TXList(list, app, settings) {
	this.sortTX = function(a, b) {
		if(a.time != b.time)
			return (a.time - b.time);

		if(a.category != b.category)
			return (b.category < a.category) ? -1 : 1;

		return (b.amount - a.amount);
	}

	this.clear = function() {
		list.children().remove();
	}

	this.processRPC = function(transactions, error) {
		if (error)
			return;

		var start = new Date().getTime();

		var transactions = jQuery.grep(transactions,
				function(n, i) {
					return n.account == app.bitcoin.settings.account;
				});

		transactions.sort(this.sortTX);

		list.children('#txlistempty').remove();

		if (transactions.length == 0)
			list.append('
no transactions
');

		for (var key in transactions)
			this.processTX(transactions[key]);

		list.children('tr:not(.txinfo):odd').addClass('odd').next('.txinfo').addClass('odd');
		list.children('tr:not(.txinfo):even').removeClass('odd').next('.txinfo').removeClass('odd');

		/* adjust refresh interval of app depending processing time of txlist */
		var end = new Date().getTime();
		var time = end - start;
		app.notify(time);
		app.setRefreshInterval(time * 10);
	}

	this.processTX = function(tx) {
		if (tx.time == undefined)
			tx.time = 0;

		if (tx.txid == undefined)
			tx.txid = (tx.time + tx.amount + tx.otheraccount).replace(/ /g,'');

		tx.txid += tx.category;

		var txrow = $(document.getElementById(tx.txid));

		if (txrow.length == 0) {
			txrow = $('

');
			list.prepend(txrow);
			var txdiv = $('

');
			txrow.after(txdiv);

			txrow.click( function() {
					var div = $(this).next('tr.txinfo').children('td').children('div');
					if (app.useSlide) div.slideToggle('fast');
					else div.toggle();
				});
		}

		var checksum = tx.txid + tx.confirmations + tx.time;

		/* Only update TX if it differs from current one */
		if(txrow.attr('checksum') != checksum) {
			txrow.attr('checksum', checksum);
			txrow.html(this.renderRow(tx));

			txrow.next('tr.txinfo').children('td').children('div').html(this.renderInfo(tx));

			if (tx.confirmations == 0 || (tx.category == "generate" && tx.confirmations < settings.generateConfirm))
				txrow.addClass("unconfirmed");
			else
				txrow.removeClass("unconfirmed");
		}
	}

	this.renderInfo = function(tx) {
		var html = "";
		var extra = "";

		switch (tx.category) {
			case "generate":
				html += "Generated coins
";
				break;
			case "move":
				html += "Moved " + (tx.amount<0?"to":"from") + ": " + tx.otheraccount.prettyAccount() + "
";
				break;
			case "send":
				if (tx.to)
					extra = " (" + tx.to + ")";
				html += "Sent to: " + tx.address + extra + "
";
				break;
			case "receive":
				if (tx.from)
					extra = " (" + tx.from + ")";
				html += "Received on: " + tx.address + extra + "
";
				break;
			default:
				html += "Category: " + tx.category + "
";
		}

		if(tx.confirmations != undefined) html += "Confirmations: " + tx.confirmations + "
";
		if(tx.fee != undefined) html += "Fee: " + tx.fee.formatBTC() + "
";
		if(tx.comment != "" && tx.comment != undefined) html += "Comment: " + tx.comment + "
";

		return html;
	}

	this.renderRow = function(tx) {
		var confirmations = tx.confirmations<10?tx.confirmations:'✓';

		if (tx.category == "generate")
			confirmations = tx.confirmations<settings.generateConfirm?'&#x2717':'&#x2713';

		var timestamp = new Date();
		timestamp.setTime (tx.time * 1000);

		var info = tx.category.capitalize();

		if (tx.category == 'send')
			if (tx.to)
				info = tx.to;
			else
				info = tx.address;

		if (tx.category == 'receive')
			if (tx.from)
				info = tx.from;
			else
				info = tx.address;

		if (tx.comment)
			info += " (" + tx.comment + ")";

		if (tx.category == 'move')
			info = (tx.amount<0?"to ":"from ") + tx.otheraccount.prettyAccount();

		var amountClass = (tx.amount<0?'debit':'credit');

		var html = '' + confirmations + '	';
		html += '' + timestamp.format(app.dateFormat) + '	';
		html += '' + info + '	';
		html += '' + tx.amount.formatBTC(true) + '	';

		return html;
	}

	this.refresh = function() {
		var size = list.children('tr').size();

		app.bitcoin.listTransactions(jQuery.proxy(this, 'processRPC'), 99999);
	}
}
<|endoftext|>


<commit_before>var fsUtil = require('../utils/fsutil');
var baseUrl = '';
var baseFolder = '../books';

describe('Comic', function() {
    var bookDB = [];
    var Book = function (name, url) {
        return {
            name: name,
            url: url
        };
    }
    var driver = browser.driver;
    function $get(url) {
        return driver.get(url);
    }
    function $(selector) {
        return driver.findElement(by.css(selector));
    }
    function saveImageToFolder(folder, count) {
        driver.isElementPresent(by.css('#defualtPagePic')).then(function(value) {
            if (value) {
                $('#defualtPagePic').getAttribute('src').then(function(url) {
                    var addr = [folder, count + '.jpg'].join('/');
                    fsUtil.download(url, addr, function(){
                        console.log('\t', addr);
                    });
                    $('.img_right.nextPageButtonJs').click();
                    saveImageToFolder(folder, count + 1);
                });
            }
        });
    }
    function saveBookFromBookDB() {
        var book = bookDB.pop();
        if (!book) {
            return;
        }
        console.log('\nDownload', book.name, 'from', book.url, '...');
        $get(book.url);
        driver.isElementPresent(by.css('.pageTitle a:nth-child(2)')).then(function(present) {
            if (present) {
                $('.pageTitle a:nth-child(2)').getText().then(function(title) {
                    var folder = [baseFolder, title].join('/');
                    fsUtil.mkdir(folder);
                    $('.pageTitle strong').getText().then(function(episode) {
                        var count = 1;
                        folder = [folder, episode].join('/');
                        fsUtil.mkdir(folder);
                        saveImageToFolder(folder, count);
                    });
                });
            } else {
                console.log('\t NOT PRESENT, SKIP!');
                saveBookFromBookDB();
            }
        });
    };

    it('Scan', function() {
        console.log('Scan BookDB ...');
        $get(baseUrl);
        $('.comicBox .relativeRec').findElements(by.tagName('li')).then(function (books) {
            books.map(function(book) {
                var link = book.findElement(by.css('h3 a'));
                link.getText().then(function (linkName) {
                    link.getAttribute('href').then(function (href) {
                        console.log('\t', linkName, '-->', href);
                        bookDB.push(new Book(linkName, href));
                    });
                });
            });
        });
    });
    it('Download', function() {
        saveBookFromBookDB();
    });
});
<commit_msg>recursive books<commit_after>var fsUtil = require('../utils/fsutil');
var baseUrl = '';
var baseFolder = '../books';

describe('Comic', function() {
    var bookDB = [];
    var Book = function (name, url) {
        return {
            name: name,
            url: url
        };
    }
    var driver = browser.driver;
    function $get(url) {
        return driver.get(url);
    }
    function $(selector) {
        return driver.findElement(by.css(selector));
    }
    function saveImageToFolder(folder, count) {
        driver.isElementPresent(by.css('#defualtPagePic')).then(function(value) {
            if (value) {
                $('#defualtPagePic').getAttribute('src').then(function(url) {
                    var addr = [folder, count + '.jpg'].join('/');
                    fsUtil.download(url, addr, function(){
                        console.log('\t', addr);
                    });
                    $('.img_right.nextPageButtonJs').click();
                    saveImageToFolder(folder, count + 1);
                });
            } else {
                saveBookFromBookDB();
            }
        });
    }
    function saveBookFromBookDB() {
        var book = bookDB.pop();
        if (!book) {
            console.log('NO BOOK, DONE!');
            return;
        }
        console.log('\nDownload', book.name, 'from', book.url, '...');
        $get(book.url);
        driver.isElementPresent(by.css('.pageTitle a:nth-child(2)')).then(function(present) {
            if (present) {
                $('.pageTitle a:nth-child(2)').getText().then(function(title) {
                    var folder = [baseFolder, title].join('/');
                    fsUtil.mkdir(folder);
                    $('.pageTitle strong').getText().then(function(episode) {
                        var count = 1;
                        folder = [folder, episode].join('/');
                        fsUtil.mkdir(folder);
                        saveImageToFolder(folder, count);
                    });
                });
            } else {
                console.log('\t NOT PRESENT, SKIP!');
                saveBookFromBookDB();
            }
        });
    };

    it('Scan', function() {
        console.log('Scan BookDB ...');
        $get(baseUrl);
        $('.comicBox .relativeRec').findElements(by.tagName('li')).then(function (books) {
            books.map(function(book) {
                var link = book.findElement(by.css('h3 a'));
                link.getText().then(function (linkName) {
                    link.getAttribute('href').then(function (href) {
                        console.log('\t', linkName, '-->', href);
                        bookDB.push(new Book(linkName, href));
                    });
                });
            });
        });
    });
    it('Download', function() {
        saveBookFromBookDB();
    });
});
<|endoftext|>


<commit_before>const baseURL = "https://intrawww.ing.puc.cl/siding"
const courseURL = "/dirdes/ingcursos/cursos"

const urls = {
  domain: "intrawww.ing.puc.cl",
  main: baseURL,
  loginURL: `${baseURL}/index.phtml`,
  currentCoursesURL: `${baseURL}${courseURL}/index.phtml`,
  coursesFromURL: (year, term) =>
    `${baseURL}${courseURL}/index.phtml?per_lista_cursos=2${term}_${year}&acc_inicio=mis_cursos`,
  courseURL: id =>
    `${baseURL}${courseURL}/index.phtml?accion_curso=avisos&id_curso_ic=${id}`,
  courseFolderURL: link => `${baseURL}${courseURL}/${link}`,
  courseFileURL: link => `https://intrawww.ing.puc.cl${link}`,
  catalogFromURL: (year, term) =>
    `${baseURL}${courseURL}/index.phtml?acc_inicio=catalogo&per_lista_cursos=2${term}_${year}`,
}

module.exports = urls
<commit_msg>fix: force 2018 - 1 for now<commit_after>const baseURL = "https://intrawww.ing.puc.cl/siding"
const courseURL = "/dirdes/ingcursos/cursos"

const urls = {
  domain: "intrawww.ing.puc.cl",
  main: baseURL,
  loginURL: `${baseURL}/index.phtml`,
  currentCoursesURL: `${baseURL}${courseURL}/index.phtml?per_lista_cursos=21_2018&acc_inicio=mis_cursos`,
  coursesFromURL: (year, term) =>
    `${baseURL}${courseURL}/index.phtml?per_lista_cursos=2${term}_${year}&acc_inicio=mis_cursos`,
  courseURL: id =>
    `${baseURL}${courseURL}/index.phtml?accion_curso=avisos&id_curso_ic=${id}`,
  courseFolderURL: link => `${baseURL}${courseURL}/${link}`,
  courseFileURL: link => `https://intrawww.ing.puc.cl${link}`,
  catalogFromURL: (year, term) =>
    `${baseURL}${courseURL}/index.phtml?acc_inicio=catalogo&per_lista_cursos=2${term}_${year}`,
}

module.exports = urls
<|endoftext|>


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

/**
  Actions are high-level executable behaviours that are typically
  triggered by users and represented as buttons or menus.

  Actions are installed as methods on the class, but contain more
  meta-information than regular methods. Meta-information includes
  information needed to surface to action in a meaningful way to
  users, and includes things like the label to appear in the button
  or menu, a speech-label for i18n, help text, dynamic functions to
  enable or disable and hide or unhide the UI associated with this Action.

  Actions implement the Action Design Pattern.
*/
foam.CLASS({
  package: 'foam.core',
  name: 'Action',

  documentation: 'An Action is a method with extra GUI support.',

  properties: [
    {
      class: 'String',
      name: 'name',
      required: true
    },
    {
      class: 'String',
      name: 'label',
      expression: function(name) { return foam.String.labelize(name); }
    },
    {
      class: 'String',
      name: 'speechLabel',
      expression: function(label) { return label; }
    },
    {
      documentation: 'displayed on :hover',
      class: 'String',
      name: 'toolTip',
      expression: function(label) { return label; }
    },
    {
      name: 'icon'
    },
    {
      class: 'String',
      name: 'iconFontFamily',
      value: 'Material Icons'
    },
    {
      class: 'String',
      name: 'iconFontClass',
      value: 'material-icons'
    },
    {
      class: 'String',
      name: 'iconFontName'
    },
    {
      class: 'Array',
      name: 'keyboardShortcuts'
    },
    {
      class: 'String',
      name: 'help'
    },
    {
      class: 'Boolean',
      name: 'isDefault',
      help: 'Indicates if this is the default action.',
      value: false
    },
    {
      class: 'Function',
      name: 'isAvailable',
      label: 'Available',
      help: 'Function to determine if action is available.',
      value: null
    },
    {
      class: 'Function',
      name: 'isEnabled',
      label: 'Enabled',
      help: 'Function to determine if action is enabled.',
      value: null
    },
    {
      class: 'Function',
      name: 'code',
      required: true,
      value: null
    }
  ],

  methods: [
    function isEnabledFor(data) {
      return this.isEnabled ?
        foam.Function.withArgs(this.isEnabled, data) :
        true;
    },

    function createIsEnabled$(data$) {
      return foam.core.ExpressionSlot.create({
        obj$: data$,
        code: this.isEnabled
      });
    },

    function isAvailableFor(data) {
      return this.isAvailable ?
        foam.Function.withArgs(this.isAvailable, data) :
        true ;
    },

    function createIsAvailable$(data$) {
      return foam.core.ExpressionSlot.create({
        obj$: data$,
        code: this.isAvailable
      });
    },

    function maybeCall(ctx, data) {
      if ( this.isEnabledFor(data) && this.isAvailableFor(data) ) {
        this.code.call(data, ctx, this);
        data && data.pub('action', this.name, this);
        return true;
      }

      return false;
    },

    function installInClass(c) {
      c.installConstant(this.name, this);
    },

    function installInProto(proto) {
      var action = this;
      proto[this.name] = function() {
        return action.maybeCall(this.__context__, this);
      };
    }
  ]
});

/** Add Action support to Model. */
foam.CLASS({
  refines: 'foam.core.Model',

  properties: [
    {
      class: 'AxiomArray',
      of: 'Action',
      name: 'actions',
      adaptArrayElement: function(o, prop) {
        return typeof o === 'function' ?
            foam.core.Action.create({name: o.name, code: o}) :
            this.lookup(prop.of).create(o) ;
      }
    }
  ]
});
<commit_msg>Change the way isEnabledFor calls isEnabled in Action.js<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
  Actions are high-level executable behaviours that are typically
  triggered by users and represented as buttons or menus.

  Actions are installed as methods on the class, but contain more
  meta-information than regular methods. Meta-information includes
  information needed to surface to action in a meaningful way to
  users, and includes things like the label to appear in the button
  or menu, a speech-label for i18n, help text, dynamic functions to
  enable or disable and hide or unhide the UI associated with this Action.

  Actions implement the Action Design Pattern.
*/
foam.CLASS({
  package: 'foam.core',
  name: 'Action',

  documentation: 'An Action is a method with extra GUI support.',

  properties: [
    {
      class: 'String',
      name: 'name',
      required: true
    },
    {
      class: 'String',
      name: 'label',
      expression: function(name) { return foam.String.labelize(name); }
    },
    {
      class: 'String',
      name: 'speechLabel',
      expression: function(label) { return label; }
    },
    {
      documentation: 'displayed on :hover',
      class: 'String',
      name: 'toolTip',
      expression: function(label) { return label; }
    },
    {
      name: 'icon'
    },
    {
      class: 'String',
      name: 'iconFontFamily',
      value: 'Material Icons'
    },
    {
      class: 'String',
      name: 'iconFontClass',
      value: 'material-icons'
    },
    {
      class: 'String',
      name: 'iconFontName'
    },
    {
      class: 'Array',
      name: 'keyboardShortcuts'
    },
    {
      class: 'String',
      name: 'help'
    },
    {
      class: 'Boolean',
      name: 'isDefault',
      help: 'Indicates if this is the default action.',
      value: false
    },
    {
      class: 'Function',
      name: 'isAvailable',
      label: 'Available',
      help: 'Function to determine if action is available.',
      value: null
    },
    {
      class: 'Function',
      name: 'isEnabled',
      label: 'Enabled',
      help: 'Function to determine if action is enabled.',
      value: null
    },
    {
      class: 'Function',
      name: 'code',
      required: true,
      value: null
    }
  ],

  methods: [
    function isEnabledFor(data) {
      return this.isEnabled ?
        data.slot(this.isEnabled).get() :
        true;
    },

    function createIsEnabled$(data$) {
      return foam.core.ExpressionSlot.create({
        obj$: data$,
        code: this.isEnabled
      });
    },

    function isAvailableFor(data) {
      return this.isAvailable ?
        foam.Function.withArgs(this.isAvailable, data) :
        true ;
    },

    function createIsAvailable$(data$) {
      return foam.core.ExpressionSlot.create({
        obj$: data$,
        code: this.isAvailable
      });
    },

    function maybeCall(ctx, data) {
      if ( this.isEnabledFor(data) && this.isAvailableFor(data) ) {
        this.code.call(data, ctx, this);
        data && data.pub('action', this.name, this);
        return true;
      }

      return false;
    },

    function installInClass(c) {
      c.installConstant(this.name, this);
    },

    function installInProto(proto) {
      var action = this;
      proto[this.name] = function() {
        return action.maybeCall(this.__context__, this);
      };
    }
  ]
});

/** Add Action support to Model. */
foam.CLASS({
  refines: 'foam.core.Model',

  properties: [
    {
      class: 'AxiomArray',
      of: 'Action',
      name: 'actions',
      adaptArrayElement: function(o, prop) {
        return typeof o === 'function' ?
            foam.core.Action.create({name: o.name, code: o}) :
            this.lookup(prop.of).create(o) ;
      }
    }
  ]
});
<|endoftext|>


<commit_before>(function(){
  var data = {
    "Link - IMDB Top 250": {type: "Link", name: "IMDB Top 250", url: "/chart/top", year:""},
  };

  var arr = [], db = localStorage.getItem("imdbac") || "{}";
  db = JSON.parse(db);
  function populateDb() {
    //Top 250 Page
    if(window.location.pathname.indexOf("/chart/top") !== -1) {
      var trArray = $("#root #main table tr");
      $(trArray).each(function(index, ele) {
        if(index) {
          var name = $(ele).find("td").eq(2).find("a").text();
          var url = $(ele).find("td").eq(2).find("a").attr("href");
          var yearText = $(ele).find("td").eq(2).text();
          var l = yearText.length;
          var year = yearText.substr(l-5, 4);
          insertIntoDb("Movie", name, url, year);
        }
      });
    }
    // Movie Page
    if(window.location.pathname.indexOf("/title/") !== -1) {
      var splt = $("#tn15title h1").text().split(" (");
      var name = splt[0];
      var url = window.location.pathname;
      var year = splt[1].split(")") [0];
      insertIntoDb("Movie", name, url, year);

      //Director
      $("#director-info a").each(function(index, node) {
         insertIntoDb("Person", $(node).text(), $(node).attr("href"), null);
      });

      //Cast
      $("#tn15main .cast .nm a").each(function(index, node) {
         insertIntoDb("Person", $(node).text(), $(node).attr("href"), null);
      });
    }
    //Person Page
    if(window.location.pathname.indexOf("/name/") !== -1) {
      var name = $("#tn15title h1").text().split(" More at") [0];
      var url = window.location.pathname;
      insertIntoDb("Person", name, url, null);
    }
  }
  populateDb();
  function insertIntoDb(type, name, url, year) {
    if(!db[type + " - " + name + (year?(" - "+year):"")]) {
      var k = {};
      k[type + " - " + name + (year?(" - "+year):"")] = {
        type: type,
        name: name,
        url: url,
        year: year
      }
      db = $.extend(db, k)
    }
  }

  localStorage.setItem("imdbac", JSON.stringify(db));
  db = jQuery.extend(db, data);
  var arr = [];
  $.each(db, function(k, v){
    arr.push(v);
  });

  var imdbSearch = $("form input[name=q]");
  imdbSearch.addClass("imdbac");
  imdbSearch.attr("autocomplete", "off");
  imdbSearch.autocomplete(arr, {
    formatMatch: function(item) {
      return item.name
    },
    formatItem: function(item) {
      var y = item.year;
      return item.name + (y?(""+y+""):"");
    },
    matchContains: true
  }).result(function(event, item) {
    location.href = "http://www.imdb.com" + item.url;
  });
}());
<commit_msg>Updated JS as per new IMDb layout.<commit_after>(function(){
  var data = {
    "Link - IMDB Top 250": {type: "Link", name: "IMDB Top 250", url: "/chart/top", year:""},
  };

  var arr = [], db = localStorage.getItem("imdbac") || "{}";
  db = JSON.parse(db);
  function populateDb() {
    //Top 250 Page
    if(window.location.pathname.indexOf("/chart/top") !== -1) {
      var trArray = $("#root #main table tr");
      $(trArray).each(function(index, ele) {
        if(index) {
          var name = $(ele).find("td").eq(2).find("a").text();
          var url = $(ele).find("td").eq(2).find("a").attr("href");
          var yearText = $(ele).find("td").eq(2).text();
          var l = yearText.length;
          var year = yearText.substr(l-5, 4);
          insertIntoDb("Movie", name, url, year);
        }
      });
    }
    // Movie Page
    if(window.location.pathname.indexOf("/title/") !== -1) {
      var splt = $("title").text().split(" - ") [0].split(" (");
      var name = splt[0];
      var url = window.location.pathname;
      var year = splt[1].split(")") [0];
      insertIntoDb("Movie", name, url, year);
      //Cast
      $("table.cast_list .name a").each(function(index, node) {
         insertIntoDb("Person", $(node).text(), $(node).attr("href"), null);
      });
    }
    //Person Page
    if(window.location.pathname.indexOf("/name/") !== -1) {
      var name = $("title").text().split(" - ") [0];
      var url = window.location.pathname;
      insertIntoDb("Person", name, url, null);
    }
  }
  populateDb();
  function insertIntoDb(type, name, url, year) {
    if(!db[type + " - " + name + (year?(" - "+year):"")]) {
      var k = {};
      k[type + " - " + name + (year?(" - "+year):"")] = {
        type: type,
        name: name,
        url: url,
        year: year
      }
      db = $.extend(db, k)
    }
  }

  localStorage.setItem("imdbac", JSON.stringify(db));
  db = jQuery.extend(db, data);
  var arr = [];
  $.each(db, function(k, v){
    arr.push(v);
  });

  var imdbSearch = $("form input[name=q]");
  imdbSearch.addClass("imdbac");
  imdbSearch.attr("autocomplete", "off");
  imdbSearch.autocomplete(arr, {
    formatMatch: function(item) {
      return item.name
    },
    formatItem: function(item) {
      var y = item.year;
      return item.name + (y?(""+y+""):"");
    },
    matchContains: true
  }).result(function(event, item) {
    location.href = "http://www.imdb.com" + item.url;
  });
}());
<|endoftext|>


<commit_before>Parse.initialize("7YyZO6oZNVongKR6pluyULEkMEmvLVRtVZvd6OXn", "JTOrsTnWqTBhxqxFMEvPdOUzDd9Ro01JqpiAF003");
window.fbAsyncInit = function() {
      Parse.FacebookUtils.init({ // this line replaces FB.init({
            appId      : '971388552927772', // Facebook App ID
            status     : true,  // check Facebook Login status
            cookie     : true,  // enable cookies to allow Parse to access the session
            xfbml      : true,  // initialize Facebook social plugins on the page
            version    : 'v2.5' // point to the latest Facebook Graph API version
      });

  // Run code after the Facebook SDK is loaded
  FB.getLoginStatus(function(response) {
    if (response.status === 'connected') {
            getUserName()
            document.getElementById("lgn-btn").style.display="none";
            document.getElementById("lgot-btn").style.display="block";
    }
    else if (response.status === 'not_authorized') {
            getUserName()
            document.getElementById("lgn-btn").style.display="none";
            document.getElementById("lgot-btn").style.display="block";
    }
});
};

function checkLoginState() {
      if (typeof FB !== 'undefined') {
            Parse.FacebookUtils.logIn("email", {
                  success: function(user) {
                        if (!user.existed()) {
                              //alert("User signed up and logged in through Facebook!");
                              getUserName()
                              document.getElementById("lgn-btn").style.display="none";
                              document.getElementById("lgot-btn").style.display="block";
                        } else {
                              //alert("User logged in through Facebook!");
                              getUserName()
                              document.getElementById("lgn-btn").style.display="none";
                              document.getElementById("lgot-btn").style.display="block";
                        }
                  },
                  error: function(user, error) {
                        alert("Please login to access the Locaholic services!!");
                  }
            },{scope:"email"});
      }
      else{
            alert("Your network does not support FaceBook Login!!")
      }
}

function getUserName() {
    FB.api('/me?fields=id,first_name,last_name,email,gender,picture', function(response) {
		document.getElementById('usrname').innerHTML = '';
		//document.getElementById('usrname').innerHTML = Parse.User.current().id + response.id + "A";
		var user = Parse.User.current();
		var firstName = user.get('firstName');
		var lastName = user.get('lastName');
	if(lastName === 'undefined' || lastName === null || lastName === '')
    	{
		alert("undefined "+lastName);
	}
	else{
		alert("defined "+lastName);
	}
    });
}
function lgOut(){
      //alert(Parse.User.current().id);
      Parse.User.logOut();
      FB.logout();
      window.location.href = "http://www.locaholic.co/";
}

(function(d, s, id){
      var js, fjs = d.getElementsByTagName(s)[0];
      if (d.getElementById(id)) {return;}
      js = d.createElement(s); js.id = id;
      js.src = "//connect.facebook.net/en_US/sdk.js";
      fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
<commit_msg>Update fb.js<commit_after>Parse.initialize("7YyZO6oZNVongKR6pluyULEkMEmvLVRtVZvd6OXn", "JTOrsTnWqTBhxqxFMEvPdOUzDd9Ro01JqpiAF003");
window.fbAsyncInit = function() {
      Parse.FacebookUtils.init({ // this line replaces FB.init({
            appId      : '971388552927772', // Facebook App ID
            status     : true,  // check Facebook Login status
            cookie     : true,  // enable cookies to allow Parse to access the session
            xfbml      : true,  // initialize Facebook social plugins on the page
            version    : 'v2.5' // point to the latest Facebook Graph API version
      });

  // Run code after the Facebook SDK is loaded
  FB.getLoginStatus(function(response) {
    if (response.status === 'connected') {
            getUserName()
            document.getElementById("lgn-btn").style.display="none";
            document.getElementById("lgot-btn").style.display="block";
    }
    else if (response.status === 'not_authorized') {
            getUserName()
            document.getElementById("lgn-btn").style.display="none";
            document.getElementById("lgot-btn").style.display="block";
    }
});
};

function checkLoginState() {
      if (typeof FB !== 'undefined') {
            Parse.FacebookUtils.logIn("email", {
                  success: function(user) {
                        if (!user.existed()) {
                              //alert("User signed up and logged in through Facebook!");
                              getUserName()
                              document.getElementById("lgn-btn").style.display="none";
                              document.getElementById("lgot-btn").style.display="block";
                        } else {
                              //alert("User logged in through Facebook!");
                              getUserName()
                              document.getElementById("lgn-btn").style.display="none";
                              document.getElementById("lgot-btn").style.display="block";
                        }
                  },
                  error: function(user, error) {
                        alert("Please login to access the Locaholic services!!");
                  }
            },{scope:"email"});
      }
      else{
            alert("Your network does not support FaceBook Login!!")
      }
}

function getUserName() {
    FB.api('/me?fields=id,first_name,last_name,email,gender,picture', function(response) {
		document.getElementById('usrname').innerHTML = '';
		//document.getElementById('usrname').innerHTML = Parse.User.current().id + response.id + "A";
		var user = Parse.User.current();
		var firstName = user.get('firstName');
		var lastName = user.get('lastName');
	if(lastName === 'undefined' || lastName === null || lastName === '')
    	{
		alert("undefined "+response.lastname);
	}
	else{
		alert("defined "+lastName);
	}
    });
}
function lgOut(){
      //alert(Parse.User.current().id);
      Parse.User.logOut();
      FB.logout();
      window.location.href = "http://www.locaholic.co/";
}

(function(d, s, id){
      var js, fjs = d.getElementsByTagName(s)[0];
      if (d.getElementById(id)) {return;}
      js = d.createElement(s); js.id = id;
      js.src = "//connect.facebook.net/en_US/sdk.js";
      fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
<|endoftext|>


<commit_before>var Net = require('net');

var Host = '127.0.0.1';
var Port = 1234;

var Header = [];
var FlightData = {};
var map;
var mapMarker;
var planeIcon;

$(document).ready(function () {
    DrawArtificalHorizon(0, 0);
    SetAltimeter(0);

    map = L.map('map').setView([43.53086, -80.5772], 17);

    planeIcon = L.icon({
        iconUrl: 'plane.png',
        iconSize: [30, 30], // size of the icon
    });

    L.tileLayer('sat_tiles/{z}/{x}/{y}.png', {
        maxZoom: 19
    }).addTo(map);

    mapMarker = L.marker([43.53086, -80.5772], {
        icon: planeIcon
    }).addTo(map);
});

function WriteToLog(text) {
    var logDiv = $('#log')
    logDiv.empty()
    var newItem = $('
' + text + '
');
    logDiv.append(newItem);
}

function ConnectHandler(err) {
    if (!err) {
        console.log('Connected: ' + Host + ':' + Port);
    }
}

function ErrorHandler(err) {
    console.log(err.code)
}

function DataHander(data) {
    if (Header.length === 0) {
        Header = data.toString().split(",");
        return
    }

    var dataSplit = data.toString().split(",");

    for (var i = 0; i < dataSplit.length; i++) {
        FlightData[Header[i]] = dataSplit[i];
    }

    WriteToLog('
' +
        'Pitch: ' + FlightData["pitch"] +
        ' Roll: ' + FlightData["roll"] +
        ' Yaw: ' + FlightData["yaw"] +
        ' Latitude: ' + FlightData["lat"] +
        ' Longitude: ' + FlightData["lon"] +
        ' Altitude: ' + FlightData["altitude"] +
        ' Heading: ' + FlightData["heading"] +
        '
');

    UpdateUI()
}

function DrawArtificalHorizon(roll, pitch) {
    //Initialize canvas
    var canvas = document.getElementById("horizon");
    canvas.height = 200;
    canvas.width = 200;
    var context = canvas.getContext("2d");
    context.clearRect(0, 0, canvas.width, canvas.height);

    //Sky
    context.fillStyle = "#03a9f4";
    context.beginPath();
    context.arc(100, 100, 100, Math.PI + roll - pitch, 2 * Math.PI + roll + pitch);
    context.fill();

    //Ground
    context.fillStyle = "#795548";
    context.beginPath();
    context.arc(100, 100, 100, 0 + roll + pitch, Math.PI + roll - pitch);
    context.fill();

    //Border
    context.strokeStyle = "black";
    context.lineWidth = 2;
    context.beginPath();
    context.arc(100, 100, 99, 0, 2 * Math.PI);
    context.stroke();

    //Center
    context.fillStyle = "black";
    context.beginPath();
    context.lineWidth = 2;
    context.arc(100, 100, 2, 0, 2 * Math.PI);
    context.fill();
    context.beginPath();
    context.moveTo(120, 100);
    context.lineTo(110, 100);
    context.stroke();
    context.arc(100, 100, 10, 0, Math.PI);
    context.stroke();
    context.lineTo(80, 100);
    context.stroke();
}

function SetAltimeter(altitude) {
    var altimeter = $('#altimeter')
    altimeter.empty()
    var newItem = $('
' + altitude + '
');
    altimeter.append(newItem);
}

function UpdateMap(lat, lon, heading) {
    map.removeLayer(mapMarker);
    mapMarker = L.marker([lat, lon], {
        icon: planeIcon
    }).addTo(map);
    var transform = $('.leaflet-marker-icon').css('transform')
    $('.leaflet-marker-icon').css('transform', transform + 'rotate(' + heading + 'deg)')
}

function UpdateUI() {
    roll = FlightData["roll"] * (Math.PI / 180);
    pitch = FlightData["pitch"] * (Math.PI / 180);
    yaw = FlightData["yaw"] * (Math.PI / 180);
    lat = FlightData["lat"];
    lon = FlightData["lon"];
    altitude = FlightData["altitude"];
    heading = FlightData["heading"];

    DrawArtificalHorizon(roll, pitch);
    SetAltimeter(altitude);

    if (!isNaN(lat) || !isNaN(lon)) {
        UpdateMap(lat, lon, heading);
    }
}

var client = new Net.Socket();

client.connect(Port, Host, ConnectHandler);
client.on('error', ErrorHandler);
client.on('data', DataHander);
client.on('close', CloseHandler);

function CloseHandler() {
    WriteToLog('Connection closed - Retrying connection');
    client = new Net.Socket();
    client.connect(Port, Host, ConnectHandler);
    client.on('error', ErrorHandler);
    client.on('data', DataHander);
    client.on('close', CloseHandler);
}<commit_msg>Popup coordinates when you click on map<commit_after>var Net = require('net');

var Host = '127.0.0.1';
var Port = 1234;

var Header = [];
var FlightData = {};
var map;
var planeMarker;
var planeIcon;
var popup = L.popup();

$(document).ready(function () {
    DrawArtificalHorizon(0, 0);
    SetAltimeter(0);

    map = L.map('map').setView([43.53086, -80.5772], 17);

    planeIcon = L.icon({
        iconUrl: 'plane.png',
        iconSize: [30, 30], // size of the icon
    });

    L.tileLayer('sat_tiles/{z}/{x}/{y}.png', {
        maxZoom: 19
    }).addTo(map);

    planeMarker = L.marker([43.53086, -80.5772], {
        icon: planeIcon
    }).addTo(map);

    map.on('click', MapClick);
});

function WriteToLog(text) {
    var logDiv = $('#log')
    logDiv.empty()
    var newItem = $('
' + text + '
');
    logDiv.append(newItem);
}

function ConnectHandler(err) {
    if (!err) {
        console.log('Connected: ' + Host + ':' + Port);
    }
}

function ErrorHandler(err) {
    console.log(err.code)
}

function DataHander(data) {
    if (Header.length === 0) {
        Header = data.toString().split(",");
        return
    }

    var dataSplit = data.toString().split(",");

    for (var i = 0; i < dataSplit.length; i++) {
        FlightData[Header[i]] = dataSplit[i];
    }

    WriteToLog('
' +
        'Pitch: ' + FlightData["pitch"] +
        ' Roll: ' + FlightData["roll"] +
        ' Yaw: ' + FlightData["yaw"] +
        ' Latitude: ' + FlightData["lat"] +
        ' Longitude: ' + FlightData["lon"] +
        ' Altitude: ' + FlightData["altitude"] +
        ' Heading: ' + FlightData["heading"] +
        '
');

    UpdateUI()
}

function DrawArtificalHorizon(roll, pitch) {
    //Initialize canvas
    var canvas = document.getElementById("horizon");
    canvas.height = 200;
    canvas.width = 200;
    var context = canvas.getContext("2d");
    context.clearRect(0, 0, canvas.width, canvas.height);

    //Sky
    context.fillStyle = "#03a9f4";
    context.beginPath();
    context.arc(100, 100, 100, Math.PI + roll - pitch, 2 * Math.PI + roll + pitch);
    context.fill();

    //Ground
    context.fillStyle = "#795548";
    context.beginPath();
    context.arc(100, 100, 100, 0 + roll + pitch, Math.PI + roll - pitch);
    context.fill();

    //Border
    context.strokeStyle = "black";
    context.lineWidth = 2;
    context.beginPath();
    context.arc(100, 100, 99, 0, 2 * Math.PI);
    context.stroke();

    //Center
    context.fillStyle = "black";
    context.beginPath();
    context.lineWidth = 2;
    context.arc(100, 100, 2, 0, 2 * Math.PI);
    context.fill();
    context.beginPath();
    context.moveTo(120, 100);
    context.lineTo(110, 100);
    context.stroke();
    context.arc(100, 100, 10, 0, Math.PI);
    context.stroke();
    context.lineTo(80, 100);
    context.stroke();
}

function SetAltimeter(altitude) {
    var altimeter = $('#altimeter')
    altimeter.empty()
    var newItem = $('
' + altitude + '
');
    altimeter.append(newItem);
}

function UpdateMap(lat, lon, heading) {
    map.removeLayer(planeMarker);
    planeMarker = L.marker([lat, lon], {
        icon: planeIcon
    }).addTo(map);
    var transform = $('.leaflet-marker-icon').css('transform')
    $('.leaflet-marker-icon').css('transform', transform + 'rotate(' + heading + 'deg)')
}

function MapClick(e) {
    popup
        .setLatLng(e.latlng)
        .setContent(e.latlng.lat + " " + e.latlng.lng)
        .openOn(map);
}

function UpdateUI() {
    roll = FlightData["roll"] * (Math.PI / 180);
    pitch = FlightData["pitch"] * (Math.PI / 180);
    yaw = FlightData["yaw"] * (Math.PI / 180);
    lat = FlightData["lat"];
    lon = FlightData["lon"];
    altitude = FlightData["altitude"];
    heading = FlightData["heading"];

    DrawArtificalHorizon(roll, pitch);
    SetAltimeter(altitude);

    if (!isNaN(lat) || !isNaN(lon)) {
        UpdateMap(lat, lon, heading);
    }
}

var client = new Net.Socket();

client.connect(Port, Host, ConnectHandler);
client.on('error', ErrorHandler);
client.on('data', DataHander);
client.on('close', CloseHandler);

function CloseHandler() {
    WriteToLog('Connection closed - Retrying connection');
    Header = [];
    client = new Net.Socket();
    client.connect(Port, Host, ConnectHandler);
    client.on('error', ErrorHandler);
    client.on('data', DataHander);
    client.on('close', CloseHandler);
}<|endoftext|>


<commit_before>var P = require('bluebird');
var async = require('async');
var config = require('../config');
var GitHubApi = require('github');
var users = require('./db').get('users');
var request = require('superagent');
P.promisifyAll(users);

function newGithub(token) {
  var api = new GitHubApi({
    version: '3.0.0'
  });
  api.authenticate({
    type: 'oauth',
    token: token
  });
  return api;
};

/**
 * Constructor for our user class
 */
function User(login, github, model) {
  this.login = login;
  this.github = github;
  this.model = model;
}

/**
 * Checks if the user is following the given username.
 */
User.prototype.isFollowing = function(other) {
  var getFollowUser = P.promisify(this.github.user.getFollowUser, this.github);
  return new P(function(resolve) {
    getFollowUser({
      user: other
    }).then(function(res) {
      return resolve(true);
    }, function(res) {
      return resolve(false);
    });
  });
};

/**
 * Follow a user.
 *
 * @param other String login username
 */
User.prototype.follow = function(other) {
  return this.isFollowing(other).bind(this).then(function(following) {
    if (following) return false;
    var followUser = P.promisify(this.github.user.followUser, this.github.user);
    return followUser({
      user: other
    });
  }).then(function(res) {
    if (!res) return false;
    return users.updateAsync({
      login: other
    }, {
      $addToSet: {
        followedBy: this.login
      }
    });
  });
};

/**
 * Make a user unfollow someone. Both params must be GH API instances.
 *
 * @param user GH API instance
 * @param other String login username
 */
User.prototype.unfollow = function(other) {
  return this.isFollowing(other).bind(this).then(function(following) {
    if (!following) return false;
    var unfollowUser = P.promisify(this.github.user.unFollowUser, this.github.user);
    return unfollowUser({
      user: other
    });
  }).then(function(res) {
    if (!res) return false;
    return users.updateAsync({
      login: other
    }, {
      $pull: {
        followedBy: this.login
      }
    });
  });
};

/**
 * Stars a repo.
 */
User.prototype.star = function(user, repo) {
  var star = P.promisify(this.github.repos.star, this.github.repos);
  return star({
    user: user,
    repo: repo
  });
};

/**
 * Adds an amount of followers to a user.
 *
 * @param amount - Use '-1' to add as many as possible. It will add as many followers as possible.
 */
User.prototype.addFollowers = function(amount) {
  var thiz = this;
  return users.findAsync({
    login: {
      $ne: this.login
    }
  }).bind(this).then(function(docs) {

    return new P(function(resolve) {
      var sum = 0;
      async.eachLimit(docs, 10, function(otherModel, done) {
        // Ignore if same as user
        if (amount !== -1 && sum >= amount) return done();

        // Otherwise follow
        var otherUser = fromModel(otherModel);
        return otherUser.follow(thiz.login).then(function(res) {
          if (res) sum++;
          done();
        }, function() {
          // OAuth token no longer valid
          thiz.invalidate().then(done, function() {
            done();
          });
        });

      }.bind(this), function() {
        resolve(sum);
      });

    }).bind(this);

  }).then(function(sum) {
    return {
      follows: sum,
      amount: amount
    };
  });

};

/**
 * Removes all of a user's followers.
 */
User.prototype.removeFollowers = function() {
  var login = this.login;
  return P.settle((this.model.followedBy || []).map(function(user) {

    return fromLogin(user).then(function(u) {
      return u.unfollow(login);
    });

  })).then(function(results) {

    var unfollowed = results.filter(function(r) {
      return r.isFulfilled();
    }).length;
    var invalid = results.filter(function(r) {
      return r.isRejected();
    }).length;

    return {
      unfollowed: unfollowed,
      invalid: invalid
    };

  });
};

/**
 * Checks the amount of followers this user is supposed to have.
 * @param login The login of the user (username)
 * @param cb(err, privilege)
 */
User.prototype.checkPrivilege = function() {
  var count = config.baseFollowers;
  return users.countAsync({
    ref: this.login
  }).bind(this).then(function(ct) {
    count += ct * config.referralBonus;
    if (this.model.god) {
      count = -1;
    }
    return {
      count: count,
      referrals: ct
    };
  });
};

/**
 * Gets all of the users that the user hasn't been followed by.
 * This is a pretty expensive operation as it makes a lot of GH api requests.
 */
User.prototype.findNotFollowedBy = function() {
  var thiz = this;

  // Get followers of user
  var followedBy = this.model.followedBy || [];

  // Find users where their login isn't one of those followedBy
  return users.findAsync({
    login: {
      $nin: followedBy,
      $ne: this.login
    }
  }).then(function(dbNotFollowing) {
    return new P(function(resolve, reject) {
      if (!dbNotFollowing) return;

      // These are the users that are not following in the DB.
      var notFollowing = [];
      async.each(dbNotFollowing, function(userObj, done) {
        if (this.login === userObj.login) return done(); // Skip if same user

        var other = fromModel(userObj);
        other.isFollowing(thiz.login).then(function(res) {
          if (!res) {
            notFollowing.push(other.login);
          }
          done();
        });

      }, function(err) {
        if (err) return reject(err);
        resolve(notFollowing);
      });
    });
  });
};

/**
 * Get users that this user is following
 */
User.prototype.getFollowing = function() {
  return users.findAsync({
    followedBy: this.login
  });
};

/**
 * Gets the models of this user's followers.
 */
User.prototype.followers = function() {
  return users.findAsync({
    login: {
      $in: this.model.followedBy
    }
  });
};

/**
 * Returns a summary of a user
 */
User.prototype.summary = function() {
  return P.props({
    privilege: this.checkPrivilege(),
    notFollowedBy: this.findNotFollowedBy()
  }).bind(this).then(function(res) {

    var followerCt = this.model.followedBy ? this.model.followedBy.length : 0;
    var remaining = res.privilege.count - followerCt;
    if (res.privilege.count === -1) {
      remaining = 99999999;
    }
    var amount = Math.min(res.notFollowedBy.length, remaining);
    if (amount < 0) amount = 0;

    return {
      privilege: res.privilege,
      amount: amount,
      remaining: remaining,
      followerCt: followerCt,
      user: this.model
    };

  });
};

/**
 * Updates this user's followers in the database.
 */
User.prototype.updateFollowedBy = function() {
  var me = this.login;
  var remove = [];

  if (!this.model.followedBy) {
    return new P(function(resolve) {
      resolve();
    });
  }

  return P.map(this.model.followedBy, function(login) {
    return fromLogin(login).then(function(user) {
      if (!user) {
        remove.push(login);
        throw 'done';
      }
      return [user, user.isFollowing(me)];
    }).spread(function(user, res) {
      if (!res) {
        remove.push(user.login);
        throw 'done';
      }
      return user;
    }).then(function(user) {
      return [user, user.validate()];
    }).spread(function(user, valid) {
      if (!valid) {
        remove.push(user.login);
      }
    }).catch(function(err) {
      if (err === 'done') return;
      console.error(err.stack);
    });
  }).then(function() {
    return users.updateAsync({
      login: me
    }, {
      $pullAll: {
        followedBy: remove
      }
    });
  }).then(function() {
    return remove;
  });
};

/**
 * Checks if a user's oauth token is valid.
 */
User.prototype.validate = function() {
  var get = P.promisify(this.github.user.get, this.github.user);
  return new P(function(resolve) {
    get({}).then(function(user) {
      request.get('https://github.com/' + user.login).end(function(res) {
        return resolve(!res.notFound);
      });
    }, function() {
      return resolve(false);
    });
  });
};

/**
 * Invalidates this user by removing their followers and deleting them from the database.
 */
User.prototype.invalidate = function() {
  var thiz = this;
  return this.getFollowing().then(function(users) {
    return P.map(users, function(model) {
      return fromModel(model).updateFollowedBy();
    });
  }).then(function() {
    return thiz.removeFollowers();
  }).then(function() {
    return thiz.remove();
  });
};

User.prototype.remove = function() {
  return users.removeAsync({
    login: this.login
  });
};

/**
 * Makes a user object from their login. Assumes it's already in the db.
 */
function fromLogin(login) {
  return users.findOneAsync({
    login: login
  }).then(function(model) {
    return new P(function(resolve) {
      if (!model) return resolve(null);
      return resolve(fromModel(model));
    });
  });
}

/**
 * Makes a (possibly new) user object from their token.
 */
function fromToken(token, ref) {
  var github = newGithub(token);
  var get = P.promisify(github.user.get, github.user);
  return get({}).then(function(result) {
    return [result, users.findOneAsync({
      login: result.login
    })];
  }).spread(function(gh, model) {
    if (model) {
      return [model.login, users.updateByIdAsync(model._id, {
        $set: {
          token: token
        }
      })];
    }

    var insert = {
      login: gh.login,
      token: token,
      avatar: gh.avatar_url
    };
    if (ref) {
      insert.ref = ref;
    }
    return [gh.login, users.insertAsync(insert)];
  }).spread(function(login) {
    return users.findOneAsync({
      login: login
    });
  }).then(function(model) {
    return fromModel(model);
  });
}

/**
 * Makes a user object from their DB model. Does not return a promise.
 */
function fromModel(model) {
  return new User(model.login, newGithub(model.token), model);
}

module.exports = {
  fromLogin: fromLogin,
  fromToken: fromToken,
  fromModel: fromModel,
  User: User
};
<commit_msg>Resolve empty promise if no followers<commit_after>var P = require('bluebird');
var async = require('async');
var config = require('../config');
var GitHubApi = require('github');
var users = require('./db').get('users');
var request = require('superagent');
P.promisifyAll(users);

function newGithub(token) {
  var api = new GitHubApi({
    version: '3.0.0'
  });
  api.authenticate({
    type: 'oauth',
    token: token
  });
  return api;
};

/**
 * Constructor for our user class
 */
function User(login, github, model) {
  this.login = login;
  this.github = github;
  this.model = model;
}

/**
 * Checks if the user is following the given username.
 */
User.prototype.isFollowing = function(other) {
  var getFollowUser = P.promisify(this.github.user.getFollowUser, this.github);
  return new P(function(resolve) {
    getFollowUser({
      user: other
    }).then(function(res) {
      return resolve(true);
    }, function(res) {
      return resolve(false);
    });
  });
};

/**
 * Follow a user.
 *
 * @param other String login username
 */
User.prototype.follow = function(other) {
  return this.isFollowing(other).bind(this).then(function(following) {
    if (following) return false;
    var followUser = P.promisify(this.github.user.followUser, this.github.user);
    return followUser({
      user: other
    });
  }).then(function(res) {
    if (!res) return false;
    return users.updateAsync({
      login: other
    }, {
      $addToSet: {
        followedBy: this.login
      }
    });
  });
};

/**
 * Make a user unfollow someone. Both params must be GH API instances.
 *
 * @param user GH API instance
 * @param other String login username
 */
User.prototype.unfollow = function(other) {
  return this.isFollowing(other).bind(this).then(function(following) {
    if (!following) return false;
    var unfollowUser = P.promisify(this.github.user.unFollowUser, this.github.user);
    return unfollowUser({
      user: other
    });
  }).then(function(res) {
    if (!res) return false;
    return users.updateAsync({
      login: other
    }, {
      $pull: {
        followedBy: this.login
      }
    });
  });
};

/**
 * Stars a repo.
 */
User.prototype.star = function(user, repo) {
  var star = P.promisify(this.github.repos.star, this.github.repos);
  return star({
    user: user,
    repo: repo
  });
};

/**
 * Adds an amount of followers to a user.
 *
 * @param amount - Use '-1' to add as many as possible. It will add as many followers as possible.
 */
User.prototype.addFollowers = function(amount) {
  var thiz = this;
  return users.findAsync({
    login: {
      $ne: this.login
    }
  }).bind(this).then(function(docs) {

    return new P(function(resolve) {
      var sum = 0;
      async.eachLimit(docs, 10, function(otherModel, done) {
        // Ignore if same as user
        if (amount !== -1 && sum >= amount) return done();

        // Otherwise follow
        var otherUser = fromModel(otherModel);
        return otherUser.follow(thiz.login).then(function(res) {
          if (res) sum++;
          done();
        }, function() {
          // OAuth token no longer valid
          thiz.invalidate().then(done, function() {
            done();
          });
        });

      }.bind(this), function() {
        resolve(sum);
      });

    }).bind(this);

  }).then(function(sum) {
    return {
      follows: sum,
      amount: amount
    };
  });

};

/**
 * Removes all of a user's followers.
 */
User.prototype.removeFollowers = function() {
  var login = this.login;
  return P.settle((this.model.followedBy || []).map(function(user) {

    return fromLogin(user).then(function(u) {
      return u.unfollow(login);
    });

  })).then(function(results) {

    var unfollowed = results.filter(function(r) {
      return r.isFulfilled();
    }).length;
    var invalid = results.filter(function(r) {
      return r.isRejected();
    }).length;

    return {
      unfollowed: unfollowed,
      invalid: invalid
    };

  });
};

/**
 * Checks the amount of followers this user is supposed to have.
 * @param login The login of the user (username)
 * @param cb(err, privilege)
 */
User.prototype.checkPrivilege = function() {
  var count = config.baseFollowers;
  return users.countAsync({
    ref: this.login
  }).bind(this).then(function(ct) {
    count += ct * config.referralBonus;
    if (this.model.god) {
      count = -1;
    }
    return {
      count: count,
      referrals: ct
    };
  });
};

/**
 * Gets all of the users that the user hasn't been followed by.
 * This is a pretty expensive operation as it makes a lot of GH api requests.
 */
User.prototype.findNotFollowedBy = function() {
  var thiz = this;

  // Get followers of user
  var followedBy = this.model.followedBy || [];

  // Find users where their login isn't one of those followedBy
  return users.findAsync({
    login: {
      $nin: followedBy,
      $ne: this.login
    }
  }).then(function(dbNotFollowing) {
    return new P(function(resolve, reject) {
      if (!dbNotFollowing) return;

      // These are the users that are not following in the DB.
      var notFollowing = [];
      async.each(dbNotFollowing, function(userObj, done) {
        if (this.login === userObj.login) return done(); // Skip if same user

        var other = fromModel(userObj);
        other.isFollowing(thiz.login).then(function(res) {
          if (!res) {
            notFollowing.push(other.login);
          }
          done();
        });

      }, function(err) {
        if (err) return reject(err);
        resolve(notFollowing);
      });
    });
  });
};

/**
 * Get users that this user is following
 */
User.prototype.getFollowing = function() {
  return users.findAsync({
    followedBy: this.login
  });
};

/**
 * Gets the models of this user's followers.
 */
User.prototype.followers = function() {
  if (!this.model.followedBy) {
    return P.resolve([]);
  }

  return users.findAsync({
    login: {
      $in: this.model.followedBy
    }
  });
};

/**
 * Returns a summary of a user
 */
User.prototype.summary = function() {
  return P.props({
    privilege: this.checkPrivilege(),
    notFollowedBy: this.findNotFollowedBy()
  }).bind(this).then(function(res) {

    var followerCt = this.model.followedBy ? this.model.followedBy.length : 0;
    var remaining = res.privilege.count - followerCt;
    if (res.privilege.count === -1) {
      remaining = 99999999;
    }
    var amount = Math.min(res.notFollowedBy.length, remaining);
    if (amount < 0) amount = 0;

    return {
      privilege: res.privilege,
      amount: amount,
      remaining: remaining,
      followerCt: followerCt,
      user: this.model
    };

  });
};

/**
 * Updates this user's followers in the database.
 */
User.prototype.updateFollowedBy = function() {
  var me = this.login;
  var remove = [];

  if (!this.model.followedBy) {
    return new P(function(resolve) {
      resolve();
    });
  }

  return P.map(this.model.followedBy, function(login) {
    return fromLogin(login).then(function(user) {
      if (!user) {
        remove.push(login);
        throw 'done';
      }
      return [user, user.isFollowing(me)];
    }).spread(function(user, res) {
      if (!res) {
        remove.push(user.login);
        throw 'done';
      }
      return user;
    }).then(function(user) {
      return [user, user.validate()];
    }).spread(function(user, valid) {
      if (!valid) {
        remove.push(user.login);
      }
    }).catch(function(err) {
      if (err === 'done') return;
      console.error(err.stack);
    });
  }).then(function() {
    return users.updateAsync({
      login: me
    }, {
      $pullAll: {
        followedBy: remove
      }
    });
  }).then(function() {
    return remove;
  });
};

/**
 * Checks if a user's oauth token is valid.
 */
User.prototype.validate = function() {
  var get = P.promisify(this.github.user.get, this.github.user);
  return new P(function(resolve) {
    get({}).then(function(user) {
      request.get('https://github.com/' + user.login).end(function(res) {
        return resolve(!res.notFound);
      });
    }, function() {
      return resolve(false);
    });
  });
};

/**
 * Invalidates this user by removing their followers and deleting them from the database.
 */
User.prototype.invalidate = function() {
  var thiz = this;
  return this.getFollowing().then(function(users) {
    return P.map(users, function(model) {
      return fromModel(model).updateFollowedBy();
    });
  }).then(function() {
    return thiz.removeFollowers();
  }).then(function() {
    return thiz.remove();
  });
};

User.prototype.remove = function() {
  return users.removeAsync({
    login: this.login
  });
};

/**
 * Makes a user object from their login. Assumes it's already in the db.
 */
function fromLogin(login) {
  return users.findOneAsync({
    login: login
  }).then(function(model) {
    return new P(function(resolve) {
      if (!model) return resolve(null);
      return resolve(fromModel(model));
    });
  });
}

/**
 * Makes a (possibly new) user object from their token.
 */
function fromToken(token, ref) {
  var github = newGithub(token);
  var get = P.promisify(github.user.get, github.user);
  return get({}).then(function(result) {
    return [result, users.findOneAsync({
      login: result.login
    })];
  }).spread(function(gh, model) {
    if (model) {
      return [model.login, users.updateByIdAsync(model._id, {
        $set: {
          token: token
        }
      })];
    }

    var insert = {
      login: gh.login,
      token: token,
      avatar: gh.avatar_url
    };
    if (ref) {
      insert.ref = ref;
    }
    return [gh.login, users.insertAsync(insert)];
  }).spread(function(login) {
    return users.findOneAsync({
      login: login
    });
  }).then(function(model) {
    return fromModel(model);
  });
}

/**
 * Makes a user object from their DB model. Does not return a promise.
 */
function fromModel(model) {
  return new User(model.login, newGithub(model.token), model);
}

module.exports = {
  fromLogin: fromLogin,
  fromToken: fromToken,
  fromModel: fromModel,
  User: User
};
<|endoftext|>


<commit_before>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
	  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
	  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
	  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

	  ga('create', 'UA-83912099-1', 'auto');
	  ga('send', 'pageview');

$( document ).ready(function() {
    var isMobile = window.matchMedia("only screen and (max-width: 760px)");
	if (isMobile.matches) {
        window.location.replace("https://shreeharshas.github.io/index.html");
    }

	/*if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
		window.location.replace("https://shreeharshas.github.io/index.html");
	}*/

	var isMobile = false; //initiate as false
// device detection
if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
    || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0,4))) isMobile = true;

 });
console.log(window.location.href);
if(isMobile){
	window.location.replace("https://shreeharshas.github.io/index.html");
}
<commit_msg>Update ga.js<commit_after>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
	  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
	  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
	  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

	  ga('create', 'UA-83912099-1', 'auto');
	  ga('send', 'pageview');

/*$( document ).ready(function() {
    var isMobile = window.matchMedia("only screen and (max-width: 760px)");
	if (isMobile.matches) {
        window.location.replace("https://shreeharshas.github.io/index.html");
    }*/

	/*if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
		window.location.replace("https://shreeharshas.github.io/index.html");
	}*/

	var isMobile = false; //initiate as false
// device detection
if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
    || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0,4))) isMobile = true;

 });

if(isMobile===true && window.location.href==="https://shreeharshas.github.io/"){
	window.location.replace("https://shreeharshas.github.io/index.html");
}
<|endoftext|>