<commit_before>var fs = require('fs');
var util = require('util');
var assert = require('assert');
var esprima = require('esprima');
var esmangle = require('esmangle');
var escodegen = require('escodegen');

var syntax = require('./syntax');
var Literal = syntax.Literal;
var Identifier = syntax.Identifier;
var MemberExpression = syntax.MemberExpression;
var Assignment = syntax.Assignment;
var BlockStatement = syntax.BlockStatement;
var FunctionDeclaration = syntax.FunctionDeclaration;
var ExpressionStatement = syntax.ExpressionStatement;
var CallExpression = syntax.CallExpression;
var ReturnStatement = syntax.ReturnStatement;
var FunctionExpression = syntax.FunctionExpression;
var CallStatement = syntax.CallStatement;

var continuationIdentifier = 'cont';
var continuationStatement = new CallStatement(new Identifier(continuationIdentifier), []);

var filename = process.argv[2];

fs.readFile(filename, 'utf-8', function(err, text) {
  transform(text);
});

function transform(code) {
  var options = {
    //loc: true,
    comment: true,
  };
  var ast = esprima.parse(code, options);
  normalizeBlock(ast);
  transformBlock(ast);
  console.log(escodegen.generate(ast));
}

function normalizeBlock(block) {
  var body = [];
  for (var i = 0; i < block.body.length; i++) {
    var statement = block.body[i];
    if (statement.type === 'IfStatement') {
      normalizeIf(statement, body);
    } else if (statement.type === 'ForStatement') {
      normalizeFor(statement, body);
    } else if (statement.type === 'WhileStatement') {
      normalizeWhile(statement, body);
    } else {
      body.push(statement);
    }
  }
  block.body = body;
}

function transformBlock(block) {
  var newBody = [];
  var place = newBody;
  var async = false;

  for (var i = 0; i < block.body.length; i++) {
    var statement = block.body[i];
    var newPlace = place;
    if (statement.type === 'ExpressionStatement') {
      newPlace = transformExpressionStatement(statement, place);
    } else if (statement.type === 'VariableDeclaration') {
      newPlace = transformDeclarations(statement, place);
    } else if (statement.type === 'IfStatement') {
      newPlace = transformIf(statement, place);
    } else if (statement.type === 'WhileStatement') {
      newPlace = transformWhile(statement, place);
    } else if (statement.type === 'ForStatement') {
      //Should not be here
      assert(false);
    } else if (statement.type === 'SwitchStatement') {
      newPlace = transformSwitch(statement, place);
    } else if (statement.type === 'FunctionDeclaration') {
      newPlace = transformFunctionDeclaration(statement, place);
    } else {
      place.push(statement);
    }
    if (newPlace !== place) {
      place = newPlace;
      async = true;
    }
  }
  block.body = newBody;
  return {
    async: async,
    place: place,
  };
}

function findContinuation(args) {
  //Todo check multiple continuations && defer
  for (var i = 0; i < args.length; i++) {
    var arg = args[i];
    if (arg.type === 'CallExpression' && arg.callee.name === 'continuation') {
      return i;
    }
  }
  return -1;
}

function continuationToCallback(args) {
  var contPos = findContinuation(args);
  if (contPos !== -1) {
    //Function call with continuation
    var contExpr = args[contPos];
    var callbackBlock = [];
    contExpr.arguments.forEach(function (arg, index) {
      callbackBlock.push(new Assignment(arg, new MemberExpression(new Identifier('arguments'), new Literal(index))));
    });

    //Replace continuation with a callback function
    args[contPos] = new FunctionExpression(
      null,
      [],
      new BlockStatement(callbackBlock)
    );
    return callbackBlock;
  }
}

function transformExpressionStatement(statement, place) {
  if (statement.expression.type === 'CallExpression') {
    return transformCall(statement, place);
  }
  if (statement.expression.type === 'AssignmentExpression') {
    return transformAssignment(statement, place);
  }

  if (statement.expression.type === 'FunctionExpression') {
    transformBlock(statement.expression.body);
  }

  place.push(statement);
  return place;
}

function transformCall(statement, place) {
  if (statement.expression.callee.type === 'FunctionExpression') {
    transformBlock(statement.expression.callee.body);
  }

  var newPlace = continuationToCallback(statement.expression.arguments);
  place.push(statement);
  if (newPlace) {
    return newPlace;
  }
  return place;
}

function transformAssignment(statement, place) {
  if (statement.expression.right.type === 'CallExpression') {
    var newPlace = continuationToCallback(statement.expression.right.arguments);
    place.push(statement);
    if (newPlace) {
      return newPlace;
    }
  } else if (statement.expression.right.type === 'FunctionExpression') {
    transformBlock(statement.expression.right.body);
    place.push(statement);
  } else {
    place.push(statement);
  }
  return place;
}

function transformDeclarations(statement, place) {
  statement.declarations.forEach(function (declaration) {
    var newPlace = null;
    if (declaration.init !== null) {
      if (declaration.init.type === 'CallExpression') {
        newPlace = continuationToCallback(declaration.init.arguments);
      } else if (declaration.init.type === 'FunctionExpression') {
        transformBlock(declaration.init.body);
      }
    }
    place.push({
      type: 'VariableDeclaration',
      kind: statement.kind,
      declarations: [declaration],
    });
    if (newPlace) {
      place = newPlace;
    }
  });
  return place;
}

function reduceDeclarations(declarations) {
  var decMap = {};
  declarations.forEach(function (dec) {
    decMap[dec.id.name] = dec;
  });
  declarations = [];
  Object.keys(decMap).forEach(function (name) {
    var dec = decMap[name];
    dec.init = null;
    declarations.push(dec);
  });
  return declarations;
}

function extractVariableDeclarations(block, declarations) {
  var normalStatements = [];
  block.body.forEach(function (statement) {
    if (statement.type === 'VariableDeclaration') {
      statement.declarations.forEach(function (dec) {
        declarations.push(dec);
        if (dec.init !== null) {
          normalStatements.push(new Assignment(dec.id, dec.init));
        }
      });
    } else {
      normalStatements.push(statement);
    }
  });
  block.body = normalStatements;
}

function normalizeIf(statement, place) {
  //Add block statement
  if (statement.consequent.type !== 'BlockStatement') {
    statement.consequent = new BlockStatement([statement.consequent]);
  }
  normalizeBlock(statement.consequent);
  if (statement.alternate === null) {
    statement.alternate = new BlockStatement([]);
  } else if (statement.alternate.type !== 'BlockStatement') {
    statement.alternate = new BlockStatement([statement.alternate]);
  }
  normalizeBlock(statement.alternate);

  //Move variable declarations outside
  var declarations = [];
  extractVariableDeclarations(statement.consequent, declarations);
  extractVariableDeclarations(statement.alternate, declarations);
  declarations = reduceDeclarations(declarations);

  place.push(new syntax.VariableDeclaration(declarations, 'var'));
  place.push(statement);
}

function normalizeWhile(statement, place) {
  if (statement.body === null) {
    statement.body = new BlockStatement([]);
  } else if (statement.body.type !== 'BlockStatement') {
    statement.body = new BlockStatement([statement.body]);
  }

  normalizeBlock(statement.body);

  //Move variable declarations outside
  var declarations = [];
  extractVariableDeclarations(statement.body, declarations);
  declarations = reduceDeclarations(declarations);

  place.push(new syntax.VariableDeclaration(declarations, 'var'));
  place.push(statement);
}

function normalizeFor(statement, place) {
  statement.type = 'WhileStatement';
  if (statement.body === null) {
    statement.body = new BlockStatement([]);
  } else if (statement.body.type !== 'BlockStatement') {
    statement.body = new BlockStatement([statement.body]);
  }
  statement.body.body.push(new ExpressionStatement(statement.update));

  place.push(statement.init);
  delete statement.init;
  delete statement.update;

  normalizeWhile(statement, place);
}

function transformIf(statement, place) {
  var consequentRes = transformBlock(statement.consequent);
  var alternateRes = transformBlock(statement.alternate);

  //Not transfrom if no async calls
  if (!consequentRes.async && !alternateRes.async) {
    place.push(statement);
    return place;
  }

  consequentRes.place.push(continuationStatement);
  alternateRes.place.push(continuationStatement);

  var nextPlace = [];
  place.push(makeCPS([statement], nextPlace));
  return nextPlace;
}

var loopCount = 0;
function getLoopFunctionName() {
  var name = 'loop_' + loopCount;
  loopCount ++;
  return name;
}

function transformWhile(statement, place) {
  if (statement.body.type !== 'BlockStatement') {
    statement.body = {
      type: 'BlockStatement',
      body: [statement.body],
    };
  }
  var blockRes = transformBlock(statement.body);

  if (blockRes.async) {
    var loopFunctionName = getLoopFunctionName();
    var nextStatement = new CallStatement(new Identifier(loopFunctionName), [new Identifier(continuationIdentifier)]);
    blockRes.place.push(nextStatement);

    var body = new BlockStatement([{
      type: 'IfStatement',
      test: statement.test,
      consequent: statement.body,
      alternate: new BlockStatement([continuationStatement]),
    }]);

    place.push(new FunctionDeclaration(
      new Identifier(loopFunctionName),
      [new Identifier(continuationIdentifier)],
      body
    ));

    var nextPlace = [];
    place.push(new CallStatement(
      new Identifier(loopFunctionName),
      [new FunctionExpression(null, [], new BlockStatement(nextPlace))]
    ));
    return nextPlace;
  }

  place.push(statement);
  return place;
}

function makeCallbackFunction(name, body) {
  return new FunctionDeclaration(
    new Identifier(name),
    [new Identifier(continuationIdentifier)],
    new BlockStatement(body)
  );
}

function makeCPS(innerPlace, nextPlace) {
  return new CallStatement(
    new FunctionExpression(
      null,
      [new Identifier(continuationIdentifier)],
      new BlockStatement(innerPlace)
    ),
    [new FunctionExpression(
      null,
      [],
      new BlockStatement(nextPlace)
    )]
  );
}

function transformSwitch(statement, place) {
  var innerPlace = [];
  var caseFunctions = [];
  var caseResults = [];
  var async = false;
  //Make case function form cases
  statement.cases.forEach(function (sCase, index) {
    var name = 'case_' + index;
    var func = makeCallbackFunction(name, sCase.consequent);
    var res = transformBlock(func.body);
    async = async || res.async;
    caseResults.push(res);
    caseFunctions.push(func);
    innerPlace.push(func);
  });

  if (!async) {
    //No need to transform
    place.push(statement);
    return place;
  }

  //Replace statements in cases with case function calls
  statement.cases.forEach(function (sCase, index) {
    var name = 'case_' + index;
    var continuationExpression = new CallExpression(new Identifier(name), [new Identifier(continuationIdentifier)]);
    sCase.consequent = [
      new ReturnStatement(continuationExpression),
    ];
  });

  caseFunctions.forEach(function (func, index) {
    var nextFunc = null;
    if (index !== caseFunctions.length - 1) {
      nextFunc = caseFunctions[index + 1];
    }
    var place = caseResults[index].place;
    place.forEach(function (statement, i) {
      //Transform break statement into continuation()
      if (statement.type === 'BreakStatement') {
        place[i] = continuationStatement;
      }
    });
    if (place.length === 0 || !isContinuationStatement(place[place.length - 1])) {
      //No break in the end, fall through into next case function
      if (nextFunc !== null) {
        place.push(new CallStatement(nextFunc.id, [new Identifier(continuationIdentifier)]));
      } else {
        place.push(continuationStatement);
      }
    }
  });

  //Add switch statement into inner place
  innerPlace.push(statement);

  var nextPlace = [];
  place.push(makeCPS(innerPlace, nextPlace));

  return nextPlace;
};

function transformFunctionDeclaration(statement, place) {
  transformBlock(statement.body);
  place.push(statement);
  return place;
}

function isContinuationStatement(statement) {
  return statement.type === 'ExpressionStatement' &&
    statement.expression.type === 'CallExpression' &&
    statement.expression.callee.name === continuationIdentifier;
}
<commit_msg>Implemented 'break' transformation in while loops.<commit_after>var fs = require('fs');
var util = require('util');
var assert = require('assert');
var esprima = require('esprima');
var esmangle = require('esmangle');
var escodegen = require('escodegen');

var syntax = require('./syntax');
var Literal = syntax.Literal;
var Identifier = syntax.Identifier;
var MemberExpression = syntax.MemberExpression;
var Assignment = syntax.Assignment;
var BlockStatement = syntax.BlockStatement;
var FunctionDeclaration = syntax.FunctionDeclaration;
var ExpressionStatement = syntax.ExpressionStatement;
var CallExpression = syntax.CallExpression;
var ReturnStatement = syntax.ReturnStatement;
var FunctionExpression = syntax.FunctionExpression;
var CallStatement = syntax.CallStatement;

var continuationIdentifier = 'cont';
var continuationStatement = new CallStatement(new Identifier(continuationIdentifier), []);

var filename = process.argv[2];

fs.readFile(filename, 'utf-8', function(err, text) {
  transform(text);
});

function transform(code) {
  var options = {
    //loc: true,
    comment: true,
  };
  var ast = esprima.parse(code, options);
  normalizeBlock(ast);
  transformBlock(ast);
  console.log(escodegen.generate(ast));
}

function normalizeBlock(block) {
  var body = [];
  for (var i = 0; i < block.body.length; i++) {
    var statement = block.body[i];
    if (statement.type === 'IfStatement') {
      normalizeIf(statement, body);
    } else if (statement.type === 'ForStatement') {
      normalizeFor(statement, body);
    } else if (statement.type === 'WhileStatement') {
      normalizeWhile(statement, body);
    } else {
      body.push(statement);
    }
  }
  block.body = body;
}

function transformBlock(block) {
  var newBody = [];
  var place = newBody;
  var async = false;

  for (var i = 0; i < block.body.length; i++) {
    var statement = block.body[i];
    var newPlace = place;
    if (statement.type === 'ExpressionStatement') {
      newPlace = transformExpressionStatement(statement, place);
    } else if (statement.type === 'VariableDeclaration') {
      newPlace = transformDeclarations(statement, place);
    } else if (statement.type === 'IfStatement') {
      newPlace = transformIf(statement, place);
    } else if (statement.type === 'WhileStatement') {
      newPlace = transformWhile(statement, place);
    } else if (statement.type === 'ForStatement') {
      //Should not be here
      assert(false);
    } else if (statement.type === 'SwitchStatement') {
      newPlace = transformSwitch(statement, place);
    } else if (statement.type === 'FunctionDeclaration') {
      newPlace = transformFunctionDeclaration(statement, place);
    } else {
      place.push(statement);
    }
    if (newPlace !== place) {
      place = newPlace;
      async = true;
    }
  }
  block.body = newBody;
  return {
    async: async,
    place: place,
  };
}

function findContinuation(args) {
  //Todo check multiple continuations && defer
  for (var i = 0; i < args.length; i++) {
    var arg = args[i];
    if (arg.type === 'CallExpression' && arg.callee.name === 'continuation') {
      return i;
    }
  }
  return -1;
}

function continuationToCallback(args) {
  var contPos = findContinuation(args);
  if (contPos !== -1) {
    //Function call with continuation
    var contExpr = args[contPos];
    var callbackBlock = [];
    contExpr.arguments.forEach(function (arg, index) {
      callbackBlock.push(new Assignment(arg, new MemberExpression(new Identifier('arguments'), new Literal(index))));
    });

    //Replace continuation with a callback function
    args[contPos] = new FunctionExpression(
      null,
      [],
      new BlockStatement(callbackBlock)
    );
    return callbackBlock;
  }
}

function transformExpressionStatement(statement, place) {
  if (statement.expression.type === 'CallExpression') {
    return transformCall(statement, place);
  }
  if (statement.expression.type === 'AssignmentExpression') {
    return transformAssignment(statement, place);
  }

  if (statement.expression.type === 'FunctionExpression') {
    transformBlock(statement.expression.body);
  }

  place.push(statement);
  return place;
}

function transformCall(statement, place) {
  if (statement.expression.callee.type === 'FunctionExpression') {
    transformBlock(statement.expression.callee.body);
  }

  var newPlace = continuationToCallback(statement.expression.arguments);
  place.push(statement);
  if (newPlace) {
    return newPlace;
  }
  return place;
}

function transformAssignment(statement, place) {
  if (statement.expression.right.type === 'CallExpression') {
    var newPlace = continuationToCallback(statement.expression.right.arguments);
    place.push(statement);
    if (newPlace) {
      return newPlace;
    }
  } else if (statement.expression.right.type === 'FunctionExpression') {
    transformBlock(statement.expression.right.body);
    place.push(statement);
  } else {
    place.push(statement);
  }
  return place;
}

function transformDeclarations(statement, place) {
  statement.declarations.forEach(function (declaration) {
    var newPlace = null;
    if (declaration.init !== null) {
      if (declaration.init.type === 'CallExpression') {
        newPlace = continuationToCallback(declaration.init.arguments);
      } else if (declaration.init.type === 'FunctionExpression') {
        transformBlock(declaration.init.body);
      }
    }
    place.push({
      type: 'VariableDeclaration',
      kind: statement.kind,
      declarations: [declaration],
    });
    if (newPlace) {
      place = newPlace;
    }
  });
  return place;
}

function reduceDeclarations(declarations) {
  var decMap = {};
  declarations.forEach(function (dec) {
    decMap[dec.id.name] = dec;
  });
  declarations = [];
  Object.keys(decMap).forEach(function (name) {
    var dec = decMap[name];
    dec.init = null;
    declarations.push(dec);
  });
  return declarations;
}

function extractVariableDeclarations(block, declarations) {
  var normalStatements = [];
  block.body.forEach(function (statement) {
    if (statement.type === 'VariableDeclaration') {
      statement.declarations.forEach(function (dec) {
        declarations.push(dec);
        if (dec.init !== null) {
          normalStatements.push(new Assignment(dec.id, dec.init));
        }
      });
    } else {
      normalStatements.push(statement);
    }
  });
  block.body = normalStatements;
}

function normalizeIf(statement, place) {
  //Add block statement
  if (statement.consequent.type !== 'BlockStatement') {
    statement.consequent = new BlockStatement([statement.consequent]);
  }
  normalizeBlock(statement.consequent);
  if (statement.alternate === null) {
    statement.alternate = new BlockStatement([]);
  } else if (statement.alternate.type !== 'BlockStatement') {
    statement.alternate = new BlockStatement([statement.alternate]);
  }
  normalizeBlock(statement.alternate);

  //Move variable declarations outside
  var declarations = [];
  extractVariableDeclarations(statement.consequent, declarations);
  extractVariableDeclarations(statement.alternate, declarations);
  declarations = reduceDeclarations(declarations);

  place.push(new syntax.VariableDeclaration(declarations, 'var'));
  place.push(statement);
}

function normalizeWhile(statement, place) {
  if (statement.body === null) {
    statement.body = new BlockStatement([]);
  } else if (statement.body.type !== 'BlockStatement') {
    statement.body = new BlockStatement([statement.body]);
  }

  normalizeBlock(statement.body);

  //Move variable declarations outside
  var declarations = [];
  extractVariableDeclarations(statement.body, declarations);
  declarations = reduceDeclarations(declarations);

  place.push(new syntax.VariableDeclaration(declarations, 'var'));
  place.push(statement);
}

function normalizeFor(statement, place) {
  statement.type = 'WhileStatement';
  if (statement.body === null) {
    statement.body = new BlockStatement([]);
  } else if (statement.body.type !== 'BlockStatement') {
    statement.body = new BlockStatement([statement.body]);
  }
  statement.body.body.push(new ExpressionStatement(statement.update));

  place.push(statement.init);
  delete statement.init;
  delete statement.update;

  normalizeWhile(statement, place);
}

function transformIf(statement, place) {
  var consequentRes = transformBlock(statement.consequent);
  var alternateRes = transformBlock(statement.alternate);

  //Not transfrom if no async calls
  if (!consequentRes.async && !alternateRes.async) {
    place.push(statement);
    return place;
  }

  consequentRes.place.push(continuationStatement);
  alternateRes.place.push(continuationStatement);

  var nextPlace = [];
  place.push(makeCPS([statement], nextPlace));
  return nextPlace;
}

var loopCount = 0;
function getLoopFunctionName() {
  var name = 'loop_' + loopCount;
  loopCount ++;
  return name;
}

function transformWhileBreak(block, continuationExpression) {
  //console.log(block.body);
  for (var i = 0; i < block.body.length; i++) {
    var statement = block.body[i];
    if (statement.type === 'BreakStatement') {
      statement = new ReturnStatement(continuationExpression);
    } else if (statement.type === 'ExpressionStatement') {
      var expression = statement.expression;
      if (expression.type === 'CallExpression') {
        if (expression.callee.type === 'FunctionExpression') {
          transformWhileBreak(expression.callee.body, continuationExpression);
        }
        expression.arguments.forEach(function (argument) {
          if (argument.type === 'FunctionExpression') {
            transformWhileBreak(argument.body, continuationExpression);
          }
        });

      }
    } else if (statement.type === 'IfStatement') {
      transformWhileBreak(statement.consequent, continuationExpression);
      transformWhileBreak(statement.alternate, continuationExpression);
    }

    block.body[i] = statement;
  }
}

function transformWhile(statement, place) {
  assert(statement.body.type === 'BlockStatement');
  var blockRes = transformBlock(statement.body);

  if (!blockRes.async) {
    place.push(statement);
    return place;
  }

  var loopFunctionName = getLoopFunctionName();
  var continuationName = loopFunctionName + '_' + continuationIdentifier;

  var nextStatement = new CallStatement(new Identifier(loopFunctionName), [new Identifier(continuationName)]);
  blockRes.place.push(nextStatement);

  var continuationStatement = new CallStatement(new Identifier(continuationName), []);

  var body = new BlockStatement([{
    type: 'IfStatement',
    test: statement.test,
    consequent: statement.body,
    alternate: new BlockStatement([continuationStatement]),
  }]);

  transformWhileBreak(statement.body, continuationStatement.expression);

  place.push(new FunctionDeclaration(
    new Identifier(loopFunctionName),
    [new Identifier(continuationName)],
    body
  ));

  var nextPlace = [];
  place.push(new CallStatement(
    new Identifier(loopFunctionName),
    [new FunctionExpression(null, [], new BlockStatement(nextPlace))]
  ));
  return nextPlace;
}

function makeCallbackFunction(name, body) {
  return new FunctionDeclaration(
    new Identifier(name),
    [new Identifier(continuationIdentifier)],
    new BlockStatement(body)
  );
}

function makeCPS(innerPlace, nextPlace) {
  return new CallStatement(
    new FunctionExpression(
      null,
      [new Identifier(continuationIdentifier)],
      new BlockStatement(innerPlace)
    ),
    [new FunctionExpression(
      null,
      [],
      new BlockStatement(nextPlace)
    )]
  );
}

function transformSwitch(statement, place) {
  var innerPlace = [];
  var caseFunctions = [];
  var caseResults = [];
  var async = false;
  //Make case function form cases
  statement.cases.forEach(function (sCase, index) {
    var name = 'case_' + index;
    var func = makeCallbackFunction(name, sCase.consequent);
    var res = transformBlock(func.body);
    async = async || res.async;
    caseResults.push(res);
    caseFunctions.push(func);
    innerPlace.push(func);
  });

  if (!async) {
    //No need to transform
    place.push(statement);
    return place;
  }

  //Replace statements in cases with case function calls
  statement.cases.forEach(function (sCase, index) {
    var name = 'case_' + index;
    var continuationExpression = new CallExpression(new Identifier(name), [new Identifier(continuationIdentifier)]);
    sCase.consequent = [
      new ReturnStatement(continuationExpression),
    ];
  });

  caseFunctions.forEach(function (func, index) {
    var nextFunc = null;
    if (index !== caseFunctions.length - 1) {
      nextFunc = caseFunctions[index + 1];
    }
    var place = caseResults[index].place;
    place.forEach(function (statement, i) {
      //Transform break statement into continuation()
      if (statement.type === 'BreakStatement') {
        place[i] = continuationStatement;
      }
    });
    if (place.length === 0 || !isContinuationStatement(place[place.length - 1])) {
      //No break in the end, fall through into next case function
      if (nextFunc !== null) {
        place.push(new CallStatement(nextFunc.id, [new Identifier(continuationIdentifier)]));
      } else {
        place.push(continuationStatement);
      }
    }
  });

  //Add switch statement into inner place
  innerPlace.push(statement);

  var nextPlace = [];
  place.push(makeCPS(innerPlace, nextPlace));

  return nextPlace;
};

function transformFunctionDeclaration(statement, place) {
  transformBlock(statement.body);
  place.push(statement);
  return place;
}

function isContinuationStatement(statement) {
  return statement.type === 'ExpressionStatement' &&
    statement.expression.type === 'CallExpression' &&
    statement.expression.callee.name === continuationIdentifier;
}
<|endoftext|>


<commit_before>const libob = require('libobject');

exports.module = (loader, subject, predicate, object) => {
    console.log('Load module:', object, '\n');
    //loader.scope.mod(object, (err, module) => {
    //    console.log(err, module);
    //});
};

exports.instance = (loader, subject, predicate, object) => {
    //console.log('Create and load instance:', object, '\n');
    // check if instance is cached
    // load instance
};

exports.listener = (loader, subject, predicate, object) => {
    //console.log('Create event', object, '\n');
};

exports.sequence = (loader, subject, predicate, object) => {
    //console.log('Create new sequence', object, '\n');
};

exports.handler = (loader, subject, predicate, object) => {
    //console.log('Create handler and add to seqence', object, '\n');
};

exports.event = (loader, subject, predicate, object) => {
    // check if sequence exists
    // 0 -> wait for sequence
    // 1 -> check if handler exists
    //      0 -> wait for handler
    //      1 -> emit flow event and pass it to handler
    //console.log('Get event stream and pipe to sequence', object, '\n');
};

exports.method = (loader, subject, predicate, object) => {
    // check if seqence exists
    // 0 -> wait for sequence
    // 1 -> check if handler exists
    //      0 -> wait for handler
    //      1 -> check if instance exists
    //           0 -> wait and try again on instance ready
    //           1 -> get method ref and pass it to handler
    //console.log('Load instance, get method ref', object, '\n');
};

exports.object = (loader, subject, predicate, object) => {
    //console.log('Build object', object, 'of type', predicate, 'attach to', subject, '\n');
};
        /*if (err || (!composition || !composition.module) || !roleAccess(composition, options.session)) {
            return loader.emit('error', err || new Error('Flow.load: No access or invalid composition'));
        }

        // emit flow events on load
        if (composition.load) {
            composition.load.forEach((event) => {
                scope.flow(event).end(options);
            });
        }

        // get cached module
        if (scope.modules[composition.module]) {
            build(scope, loader, composition, scope.modules[composition.module]);
            return;
        }

        loader.once('module', (module) => {
            scope.modules[composition.module] = module;
            build(scope, loader, composition, module);
        });

        if (scope.modules[composition.module] === null) {
            return;
        }

        scope.modules[composition.module] = null;
        scope.mod(composition.module, options, (err, module) => {

            if (err) {
                return loader.emit('error', err);
            }

            loader.emit('module', module);
        });
    });
}

function roleAccess (item, role) {

    var roles = item && (item._roles || item.roles || {}) || {};
    role = role && role.role ? role.role : role;

    if (roles['*'] || (typeof role === 'string' && roles[role])) {
        return true;
    }
}

function build (scope, loader, config, module) {

    // create new flow emitter
    var instance = Object.create(module);
    instance.flow = scope.flow.bind(null, config.name);
    instance._name = config.name;
    instance._reset = scope.reset;
    instance._config = config.config || {};

    // extend loader
    loader.module = config.module;
    loader.name = config.name;
    loader.roles = config.roles || {};
    loader.flow = config.flow || {};
    loader.parsed = {};

    var ready = function (err, data) {

        if (err) {
            return loader.emit('error', err);
        }

        // mark instance as ready
        loader.inst = instance;
        loader.ready = true;
        loader.emit('ready', loader);
    };

    // init loader instance
    instance.init ? instance.init(config.config || {}, ready) : ready();
}*/

function parse (scope, event, event_id, options, instance) {

    var sequence = scope.events[event_id];

    if (!instance.flow || !instance.flow[event]) {
        return sequence.emit('error', new Error('Flow.parse: Event "' + event + '" not found on instance "' + instance.name + '".'));
    }

    if (!instance.flow[event].d) {
        return sequence.emit('error', new Error('Flow.parse: No data handlers.'));
    }

    var parsedEvent = parseEvent(scope, instance, instance.flow[event].d);
    var count = 0;
    var check = function () {
        if (++count === parsedEvent.l.length) {
            parseSequence(scope, sequence, parsedEvent.s);
        }
    };

    // set instance ref
    sequence.i = instance;

    // set end and error events
    sequence.e = instance.flow[event].e;
    sequence.r = instance.flow[event].r;

    if (parsedEvent.l.length > 0) {
        parsedEvent.l.forEach(function (instName) {
            Load(scope, sequence, instName, options, check);
        });

    } else {
        parseSequence(scope, sequence, parsedEvent.s);
    }
}

function parseEvent (scope, instance, config) {

    var instances = {};
    var sequences = [];
    var pointer = 0;

    config.forEach(function (handler) {

        // resolve handler
        var path = handler;
        var args = {};

        if (handler.constructor === Array) {
            path = handler[0];
            args = handler[1] || {};
        }

        let type = path.substr(0, 1);
        path = path.substr(1);

        // parse path
        let instance_name = instance.name;
        if (path.indexOf('/') > 0) {
            path = path.split('/', 2);
            instance_name = path[0];
            path = path[1];
        }

        if (!scope.instances[instance_name] || !scope.instances[instance_name].ready) {
            instances[instance_name] = 1;
        }

        switch (type) {

            // data handlers
            case ':':
            case '.':

                // create new section if current is a even/stream handler
                if (sequences[pointer] && sequences[pointer][0] > 0) {
                    ++pointer;
                }

                sequences[pointer] = sequences[pointer] || [0, []];
                sequences[pointer][1].push([instance_name, path, args, (type === '.')]);
                return;

            // stream handlers
            case '>':
            case '*':

                sequences.push([(type === '*' ? 1 : 2), [instance_name, path, args]]);

                ++pointer;
                return;
        }

        sequence.emit('error', new Error('Flow.parse: Invalid handler type:', type));
    });

    return {
        l: Object.keys(instances),
        s: sequences
    };
}

// update sequences with method refs
function parseSequence (scope, event, sequences) {

    var getMethodRef = function (handler) {
        handler[0] = scope.instances[handler[0]].inst;

        if (!(handler[1] = libob.path(handler[1], handler[0]))) {
            return event.emit('error', new Error('Flow.parse: Method on instance "' + handler[0]._name + '" not found.'));
        }
    };

    for (var i = 0, l = sequences.length, sequence; i < l; ++i) {
        sequence = sequences[i];

        switch (sequence[0]) {
            case 0:
                sequence[1].forEach(getMethodRef);
                break;
            case 1:
                getMethodRef(sequence[1]);
                break;
            case 2:
                sequence[1][0] = scope.instances[sequence[1][0]].inst;
        }
    }

    event.s = sequences;
    event.ready = true;
    event.emit('ready', event);
}
<commit_msg>adjust exported methods to rule changes<commit_after>const libob = require('libobject');

exports.module = (loader, subject, predicate, object) => {
    console.log('Load module:', object);
    //loader.scope.mod(object, (err, module) => {
    //    console.log(err, module);
    //});
};

exports.instance = (loader, subject, predicate, object) => {
    console.log('Create and load instance:', object);
    // check if instance is cached
    // load instance
};

exports.event = (loader, subject, predicate, object) => {
    //console.log('Create event', object, '\n');
};

exports.emit = (loader, subject, predicate, object) => {
    let instance = object;
    let event = object;
    loader.scope.flow(object);
};

exports.sequence = (loader, subject, predicate, object) => {
    //console.log('Create new sequence', object, '\n');
};

exports.dataHandler = (loader, subject, predicate, object) => {
    //console.log('Create handler and add to seqence', object, '\n');
    // check if seqence exists
    // 0 -> wait for sequence
    // 1 -> check if handler exists
    //      0 -> wait for handler
    //      1 -> check if instance exists
    //           0 -> wait and try again on instance ready
    //           1 -> get method ref and pass it to handler
    //console.log('get method ref', object, '\n');
};

exports.streamHandler = (loader, subject, predicate, object) => {
    console.log('Create handler and add to seqence', object, '\n');
};

exports.eventHandler = (loader, subject, predicate, object) => {
    // check if sequence exists
    // 0 -> wait for sequence
    // 1 -> check if handler exists
    //      0 -> wait for handler
    //      1 -> emit flow event and pass it to handler
    console.log('Get event stream and pipe to sequence', object, '\n');
};

exports.object = (loader, subject, predicate, object) => {
   // console.log('Build object', object, 'of type', predicate, 'attach to', subject, '\n');
};
        /*if (err || (!composition || !composition.module) || !roleAccess(composition, options.session)) {
            return loader.emit('error', err || new Error('Flow.load: No access or invalid composition'));
        }

        // emit flow events on load
        if (composition.load) {
            composition.load.forEach((event) => {
                scope.flow(event).end(options);
            });
        }

        // get cached module
        if (scope.modules[composition.module]) {
            build(scope, loader, composition, scope.modules[composition.module]);
            return;
        }

        loader.once('module', (module) => {
            scope.modules[composition.module] = module;
            build(scope, loader, composition, module);
        });

        if (scope.modules[composition.module] === null) {
            return;
        }

        scope.modules[composition.module] = null;
        scope.mod(composition.module, options, (err, module) => {

            if (err) {
                return loader.emit('error', err);
            }

            loader.emit('module', module);
        });
    });
}

function roleAccess (item, role) {

    var roles = item && (item._roles || item.roles || {}) || {};
    role = role && role.role ? role.role : role;

    if (roles['*'] || (typeof role === 'string' && roles[role])) {
        return true;
    }
}

function build (scope, loader, config, module) {

    // create new flow emitter
    var instance = Object.create(module);
    instance.flow = scope.flow.bind(null, config.name);
    instance._name = config.name;
    instance._reset = scope.reset;
    instance._config = config.config || {};

    // extend loader
    loader.module = config.module;
    loader.name = config.name;
    loader.roles = config.roles || {};
    loader.flow = config.flow || {};
    loader.parsed = {};

    var ready = function (err, data) {

        if (err) {
            return loader.emit('error', err);
        }

        // mark instance as ready
        loader.inst = instance;
        loader.ready = true;
        loader.emit('ready', loader);
    };

    // init loader instance
    instance.init ? instance.init(config.config || {}, ready) : ready();
}*/

function parse (scope, event, event_id, options, instance) {

    var sequence = scope.events[event_id];

    if (!instance.flow || !instance.flow[event]) {
        return sequence.emit('error', new Error('Flow.parse: Event "' + event + '" not found on instance "' + instance.name + '".'));
    }

    if (!instance.flow[event].d) {
        return sequence.emit('error', new Error('Flow.parse: No data handlers.'));
    }

    var parsedEvent = parseEvent(scope, instance, instance.flow[event].d);
    var count = 0;
    var check = function () {
        if (++count === parsedEvent.l.length) {
            parseSequence(scope, sequence, parsedEvent.s);
        }
    };

    // set instance ref
    sequence.i = instance;

    // set end and error events
    sequence.e = instance.flow[event].e;
    sequence.r = instance.flow[event].r;

    if (parsedEvent.l.length > 0) {
        parsedEvent.l.forEach(function (instName) {
            Load(scope, sequence, instName, options, check);
        });

    } else {
        parseSequence(scope, sequence, parsedEvent.s);
    }
}

function parseEvent (scope, instance, config) {

    var instances = {};
    var sequences = [];
    var pointer = 0;

    config.forEach(function (handler) {

        // resolve handler
        var path = handler;
        var args = {};

        if (handler.constructor === Array) {
            path = handler[0];
            args = handler[1] || {};
        }

        let type = path.substr(0, 1);
        path = path.substr(1);

        // parse path
        let instance_name = instance.name;
        if (path.indexOf('/') > 0) {
            path = path.split('/', 2);
            instance_name = path[0];
            path = path[1];
        }

        if (!scope.instances[instance_name] || !scope.instances[instance_name].ready) {
            instances[instance_name] = 1;
        }

        switch (type) {

            // data handlers
            case ':':
            case '.':

                // create new section if current is a even/stream handler
                if (sequences[pointer] && sequences[pointer][0] > 0) {
                    ++pointer;
                }

                sequences[pointer] = sequences[pointer] || [0, []];
                sequences[pointer][1].push([instance_name, path, args, (type === '.')]);
                return;

            // stream handlers
            case '>':
            case '*':

                sequences.push([(type === '*' ? 1 : 2), [instance_name, path, args]]);

                ++pointer;
                return;
        }

        sequence.emit('error', new Error('Flow.parse: Invalid handler type:', type));
    });

    return {
        l: Object.keys(instances),
        s: sequences
    };
}

// update sequences with method refs
function parseSequence (scope, event, sequences) {

    var getMethodRef = function (handler) {
        handler[0] = scope.instances[handler[0]].inst;

        if (!(handler[1] = libob.path(handler[1], handler[0]))) {
            return event.emit('error', new Error('Flow.parse: Method on instance "' + handler[0]._name + '" not found.'));
        }
    };

    for (var i = 0, l = sequences.length, sequence; i < l; ++i) {
        sequence = sequences[i];

        switch (sequence[0]) {
            case 0:
                sequence[1].forEach(getMethodRef);
                break;
            case 1:
                getMethodRef(sequence[1]);
                break;
            case 2:
                sequence[1][0] = scope.instances[sequence[1][0]].inst;
        }
    }

    event.s = sequences;
    event.ready = true;
    event.emit('ready', event);
}
<|endoftext|>


<commit_before>import Rx from 'rx';
import React from 'react';
import ReactDOM from 'react-dom';
import compose from './compose';
import { StreamWrapper, dispatch } from './streamWrapper.js';

const identity = (value) => value;

class Root extends React.Component {
  constructor(props) {
    super(props);
    this.state = props;
  }

  render() {
    return React.createElement(
      this.props.view,
      this.state
    )
  }
}

/**
 * @typedef TanokReturnValue
 * @type { Object }
 * @property { Object } disposable - Returns disposable that can be used for observers disposing.
 * @property { Object } eventStream - Your app inner eventStream.
 * */

/**
 * App-initialization function.
 * @param { Object } initialState - Initial state of your application.
 * @param { Array } update - Array of pairs "predicate - state mutator",
 * declarative statement of your events dispatching. Usually - result of dispatcher.collect() invocation.
 * @param { class } view - Your root component class.
 * @param { Object } options - Advanced app configuration
 * @param { HTMLElement } options.container - Root node of your application.
 * If not provided - new "div" will be added and appended to document.body .
 * @param { Object } options.outerEventStream - Yet another stream that will be merged to your app inner stream.
 * @param { Function } options.stateSerializer - Advanced function to serialize your model before passing to view as props.
 * @param { Array } options.middlewares - List of middlewares.
 * @returns { TanokReturnValue } - Returns disposable as result of your observers applying,
 * and your app inner eventStream.
 * */
export function tanok(initialState, update, view, options) {
  let { container, outerEventStream, stateSerializer = identity, middlewares=[] } = options || {};
  if (!container) {
    container = document.createElement('div');
    document.body.appendChild(container);
  }

  const eventStream = new Rx.Subject();
  const rootParent = null;
  let dispatcher = dispatch(eventStream, update, rootParent);
  const streamWrapper = new StreamWrapper(eventStream, rootParent);
  let component;

  dispatcher = dispatcher
    .scan((({state}, action) => {
      const appliedMiddleware = compose(...middlewares)(action);
      const {state: newState, effects, params: params} = appliedMiddleware(state);
      return {state: newState, effects, params: params}
    }), {state: initialState})
    .startWith({state: initialState});

  streamWrapper.disposable = dispatcher
    .do(({state}) => component && component.setState(stateSerializer(state)))
    .do(({effects=[]}) =>
      effects.forEach((e) =>
        Rx.Observable.spawn(e(streamWrapper))
        .flatMap((obs) => obs || [])
        .subscribe(
          Rx.helpers.noop,
          console.error.bind(console)
        )
      )
    )
    .subscribe(
      Rx.helpers.noop,
      console.error.bind(console)
    );

  streamWrapper.send('init');

  component = ReactDOM.render(
    React.createElement(
      Root,
      {
        view,
        tanokStream: streamWrapper,
        eventStream: streamWrapper,
        ...stateSerializer(initialState),
      }
    ),
    container
  )

  if (outerEventStream) {
    outerEventStream.subscribe(
      streamWrapper.stream.onNext.bind(streamWrapper.stream),
      console.error.bind(console)
    )
  }

  return {
    disposable: streamWrapper.disposable,
    eventStream,
    component,
  };
}

export function effectWrapper(effect, parent) {
  return (streamWrapper) => {
    const substream = streamWrapper.subs[parent];
    if (!substream) {
      throw new Error(`No such substream '${parent}'`)
    }

    return effect
      ? effect(substream)
      : Rx.helpers.noop;
  };
}

/**
* Usage example:
* class HelloWorldDispatcher extends TanokDispatcher {
*
*   @on('helloEvent')
*   helloWorld (eventPayload, state) {
*     state.word = eventPayload.word;
*     return [state, helloWorldEffect];
*   }
* }
*
* var helloWorldDispatcher = new HelloWorldDispatcher();
* tanok(HelloWorldModel, helloWorldDispatcher.collect(), ViewComponent, {container})
* */
export class TanokDispatcher {
  [Symbol.iterator]() {
    function makeIterator(array){
        var nextIndex = 0;

        return {
           next: function(){
               return nextIndex < array.length ?
                   {value: array[nextIndex++], done: false} :
                   {done: true};
           }
        };
    }

    return makeIterator(this.collect());
  }

  collect() {
    return this.events.map(([predicate, stateMutator]) => [predicate, stateMutator.bind(this)]);
  }
}
<commit_msg>move composing of middlewares<commit_after>import Rx from 'rx';
import React from 'react';
import ReactDOM from 'react-dom';
import compose from './compose';
import { StreamWrapper, dispatch } from './streamWrapper.js';

const identity = (value) => value;

class Root extends React.Component {
  constructor(props) {
    super(props);
    this.state = props;
  }

  render() {
    return React.createElement(
      this.props.view,
      this.state
    )
  }
}

/**
 * @typedef TanokReturnValue
 * @type { Object }
 * @property { Object } disposable - Returns disposable that can be used for observers disposing.
 * @property { Object } eventStream - Your app inner eventStream.
 * */

/**
 * App-initialization function.
 * @param { Object } initialState - Initial state of your application.
 * @param { Array } update - Array of pairs "predicate - state mutator",
 * declarative statement of your events dispatching. Usually - result of dispatcher.collect() invocation.
 * @param { class } view - Your root component class.
 * @param { Object } options - Advanced app configuration
 * @param { HTMLElement } options.container - Root node of your application.
 * If not provided - new "div" will be added and appended to document.body .
 * @param { Object } options.outerEventStream - Yet another stream that will be merged to your app inner stream.
 * @param { Function } options.stateSerializer - Advanced function to serialize your model before passing to view as props.
 * @param { Array } options.middlewares - List of middlewares.
 * @returns { TanokReturnValue } - Returns disposable as result of your observers applying,
 * and your app inner eventStream.
 * */
export function tanok(initialState, update, view, options) {
  let { container, outerEventStream, stateSerializer = identity, middlewares=[] } = options || {};
  if (!container) {
    container = document.createElement('div');
    document.body.appendChild(container);
  }

  const eventStream = new Rx.Subject();
  const rootParent = null;
  let dispatcher = dispatch(eventStream, update, rootParent);
  const streamWrapper = new StreamWrapper(eventStream, rootParent);
  let component;
  const composedMiddlewares = compose(...middlewares);

  dispatcher = dispatcher
    .scan((({state}, action) => {
      const appliedMiddleware = composedMiddlewares(action);
      const {state: newState, effects, params: params} = appliedMiddleware(state);
      return {state: newState, effects, params: params}
    }), {state: initialState})
    .startWith({state: initialState});

  streamWrapper.disposable = dispatcher
    .do(({state}) => component && component.setState(stateSerializer(state)))
    .do(({effects=[]}) =>
      effects.forEach((e) =>
        Rx.Observable.spawn(e(streamWrapper))
        .flatMap((obs) => obs || [])
        .subscribe(
          Rx.helpers.noop,
          console.error.bind(console)
        )
      )
    )
    .subscribe(
      Rx.helpers.noop,
      console.error.bind(console)
    );

  streamWrapper.send('init');

  component = ReactDOM.render(
    React.createElement(
      Root,
      {
        view,
        tanokStream: streamWrapper,
        eventStream: streamWrapper,
        ...stateSerializer(initialState),
      }
    ),
    container
  )

  if (outerEventStream) {
    outerEventStream.subscribe(
      streamWrapper.stream.onNext.bind(streamWrapper.stream),
      console.error.bind(console)
    )
  }

  return {
    disposable: streamWrapper.disposable,
    eventStream,
    component,
  };
}

export function effectWrapper(effect, parent) {
  return (streamWrapper) => {
    const substream = streamWrapper.subs[parent];
    if (!substream) {
      throw new Error(`No such substream '${parent}'`)
    }

    return effect
      ? effect(substream)
      : Rx.helpers.noop;
  };
}

/**
* Usage example:
* class HelloWorldDispatcher extends TanokDispatcher {
*
*   @on('helloEvent')
*   helloWorld (eventPayload, state) {
*     state.word = eventPayload.word;
*     return [state, helloWorldEffect];
*   }
* }
*
* var helloWorldDispatcher = new HelloWorldDispatcher();
* tanok(HelloWorldModel, helloWorldDispatcher.collect(), ViewComponent, {container})
* */
export class TanokDispatcher {
  [Symbol.iterator]() {
    function makeIterator(array){
        var nextIndex = 0;

        return {
           next: function(){
               return nextIndex < array.length ?
                   {value: array[nextIndex++], done: false} :
                   {done: true};
           }
        };
    }

    return makeIterator(this.collect());
  }

  collect() {
    return this.events.map(([predicate, stateMutator]) => [predicate, stateMutator.bind(this)]);
  }
}
<|endoftext|>


<commit_before>const reportTo = [
  {
    titleEN: "How to make a report",
    titlePK: "رپورٹ کرنا",
  },
  {
    titleEN: "Reporting to FIA",
    titlePK: "مختار کاروں کو رپورٹ کرنا",
    textEN: "Do not stay quiet if you are being harassed online. Cyber Crimes must be reported to the FIA National Response Center for Cyber Crime. The FIA’s Cyber Crime Wing offices are located in Karachi, Lahore, Quetta, Peshawar, Rawalpindi, Islamabad. The FIA’s helpline is 9911 and they can also be contacted on the following online form",
    textPK: "اگر آپ کو آن لائن ہراساں کیا گیا ہے تو چپ نہ بیٹھیں۔ ایف آئی اے کے ادارے کو ان کے آن لائن سائبر کمپلینٹ سروس پر سائبر ہراسانی کی رپورٹ کریں۔ وہاں آپ کو ایک مختصر سا فارم ملے گا جسے آپ کو پر کرنا ہے لیکن اس بات کی تسلی کرلیں کہ جس حد تک آپ کو ہراسانی کا سامنا ہوا ہے اس کے مطابق تفصیلات سے آگاہ کریں۔ آپ کی درج شکایت پر عمل پیرا ہونے میں انہیں 24 گھنٹے کا وقت درکار ہوگا۔",
    button1: "http://www.nr3c.gov.pk/creport.php"
  },
  {
    titleEN: "Reporting to PTA",
    titlePK: "رپورٹ کرنا",
    textEN: "Pakistan Telecommunication Authority is there to report harassment on text messages and calls. Their numbers are the following: 0800-55055 and 051-9225329-31",
    textPK: "Pakistan Telecommunication Authority is there to report harassment on text messages and calls. Their numbers are the following: 0800-55055 and 051-9225329-31"
  },
  {
    titleEN: "Cyber Harassment Helpline",
    titlePK: "رپورٹ کرنا",
    textEN: "",
    textPK: ""
  },
  {
    titleEN: "Reporting Harassment on Facebook",
    titlePK: "فیس بک پہ رپورٹ کرنا",
    textEN: "Facebook has a report button for almost every element on the site: profiles, posts, photos, messages and groups. Therefore there isn’t one centralised report procedure. However they have a page of examples so you can find out how to report any type of harassment you experience on the site.",
    textPK: "پروفائلز، پوسٹس، فوٹوز، میسجز اور گروپس میں :فیس بک سائٹ پر ہر عنصر کیلئے ایک رپورٹ بٹن ہوتا ہے۔ اس لئے اس کا کوئی مرکزی رپورٹ کرنے کا طریقہ کار نہیں ہوتا۔ تاہم وہ نمونے کے طور پر ایک پیج رکھتے ہیں تاکہ سائٹ پر آپ کو کسی قسم کی ہراسانی کا سامنا کرنے پر آپ رپورٹ کر سکیں۔"
  },
  {
    titleEN: "Reporting Harassment on Twitter",
    titlePK: "ٹویٹر پر رپورٹ کرنا",
    textEN: "Twitter has a few reporting methods. Most, like Facebook, are buttons next to the content itself. But they also have separate report forms for things like impersonation accounts or doxing. They will usually then email you a response. Click the following link to report cyber harassment on Twitter: https://support.twitter.com/",
    textPK: "ٹویٹر پر رپورٹ کرنے کے چند ضوابط لاگو ہیں۔ فیس بک جیسے زیادہ تر سوشل میڈیا چینلز پر ان کے مواد کیساتھ ہی چند بٹن ہوتے ہیں۔ لیکن ان کے پاس الگ سے رپورٹ کرنے کی اقسام  بھی ہوتی ہیں جیسے دوہری شخصیتی اکاؤنٹ یا  ۔ پھر بعدازاں آپ کو ایک ای میل کے ذریعے جواب بھیج دیا جاتا ہے"
  },
  {
    titleEN: "Reporting Harassment on Instagram",
    titlePK: "انسٹا گرام پہ رپورٹ کرنا",
    textEN: "Like other social media accounts, Instagram profiles can also be attacked and hate accounts have been set up to target women in the past. Instagram has processes for reporting accounts and posts, and they can accept reports whether you have an account of your own or not. To keep yourself safe on Instagram report it on the following link: https://help.instagram.com/",
    textPK: "ماضی میں خواتین کو نشانہ بنانے کیلئے دیگر سوشل میڈیا اکاؤنٹس کی طرح انسٹا گرام پروفائلز پر بھی نفرت انگیز اور حملہ آور اکاؤنٹس ترتیب دیئے جا سکتے ہیں۔ اس زمرے میں انسٹا گرام پہ اکاؤنٹس اور پوسٹس کی  رپورٹ کرنے کیلئے ایک طریقہ کار مرتب ہے اور وہ آپ کی درج کی گئی رپورٹ کو وصول کرسکتے ہیں چاہے آپ کا اپنا اکاؤنٹ موجود ہو یا نہ ہو۔"
  },
  {
    titleEN: "Reporting Harassment on Snapchat",
    titlePK: "سنیپ چیٹ پہ رپورٹ کرنا",
    textEN: "The harassment may not be on the screen for long, but the distress can last a long time. To fight back, Snapchat offers a general reporting form that allows you to submit information about safety concerns. So if you’ve received a harassing image or message, an account is bullying you or you’ve been hacked, you can report it this way. Take a step and report cyber harassment on this link: https://support.snapchat.com/en-US/404",
    textPK: "اگرچہ ہراسانی کسی بھی سکرین پر بہت دیر تک نہیں رہ سکتی لیکن اس کے اثرات سے ہونے والی پریشانی تا دیر رہتی ہے۔ اس سے نبرد آزما ہونے کیلئے سنیپ چیٹ آپ کو ایک عمومی فارم تجویز کرتا ہے جو آپ کو دفاعی خدشات سے متعلق معلومات جمع کرنے کی اجازت دیتا ہے۔ لہٰذا اگر آپ کو کوئی ہراسانی سے بھرپور کوئی تصویر یا پیغام موصول ہوتا ہے، کسی اکاؤنٹ سے آپ کو تنگ کیا جاتاہے یا آپ کو ہیک کرلیا گیا ہے تو آپ اس طریقے سے رپورٹ کر سکتے ہیں۔"
  },
];

export {reportTo};
<commit_msg>added translations for reporting to PTA<commit_after>const reportTo = [
  {
    titleEN: "How to make a report",
    titlePK: "رپورٹ کرنا",
  },
  {
    titleEN: "Reporting to FIA",
    titlePK: "مختار کاروں کو رپورٹ کرنا",
    textEN: "Do not stay quiet if you are being harassed online. Cyber Crimes must be reported to the FIA National Response Center for Cyber Crime. The FIA’s Cyber Crime Wing offices are located in Karachi, Lahore, Quetta, Peshawar, Rawalpindi, Islamabad. The FIA’s helpline is 9911 and they can also be contacted on the following online form",
    textPK: "اگر آپ کو آن لائن ہراساں کیا گیا ہے تو چپ نہ بیٹھیں۔ ایف آئی اے کے ادارے کو ان کے آن لائن سائبر کمپلینٹ سروس پر سائبر ہراسانی کی رپورٹ کریں۔ وہاں آپ کو ایک مختصر سا فارم ملے گا جسے آپ کو پر کرنا ہے لیکن اس بات کی تسلی کرلیں کہ جس حد تک آپ کو ہراسانی کا سامنا ہوا ہے اس کے مطابق تفصیلات سے آگاہ کریں۔ آپ کی درج شکایت پر عمل پیرا ہونے میں انہیں 24 گھنٹے کا وقت درکار ہوگا۔",
    button1: "http://www.nr3c.gov.pk/creport.php"
  },
  {
    titleEN: "Reporting to PTA",
    titlePK: "پی۔ٹی۔اے کو رپورٹ کرنا",
    textEN: "Pakistan Telecommunication Authority is there to report harassment on text messages and calls. Their numbers are the following: 0800-55055 and 051-9225329-31",
    textPK: "ہراسانی کی صورت میں پاکستان ٹیلی کمیونیکیشن اتھارٹی کو شکایت مندرجہ ذیل نمبروں پر بذریعہ کال یا پیغام کریں:0800-55055 051-9225329-31"
  },
  {
    titleEN: "Cyber Harassment Helpline",
    titlePK: "رپورٹ کرنا",
    textEN: "",
    textPK: ""
  },
  {
    titleEN: "Reporting Harassment on Facebook",
    titlePK: "فیس بک پہ رپورٹ کرنا",
    textEN: "Facebook has a report button for almost every element on the site: profiles, posts, photos, messages and groups. Therefore there isn’t one centralised report procedure. However they have a page of examples so you can find out how to report any type of harassment you experience on the site.",
    textPK: "پروفائلز، پوسٹس، فوٹوز، میسجز اور گروپس میں :فیس بک سائٹ پر ہر عنصر کیلئے ایک رپورٹ بٹن ہوتا ہے۔ اس لئے اس کا کوئی مرکزی رپورٹ کرنے کا طریقہ کار نہیں ہوتا۔ تاہم وہ نمونے کے طور پر ایک پیج رکھتے ہیں تاکہ سائٹ پر آپ کو کسی قسم کی ہراسانی کا سامنا کرنے پر آپ رپورٹ کر سکیں۔"
  },
  {
    titleEN: "Reporting Harassment on Twitter",
    titlePK: "ٹویٹر پر رپورٹ کرنا",
    textEN: "Twitter has a few reporting methods. Most, like Facebook, are buttons next to the content itself. But they also have separate report forms for things like impersonation accounts or doxing. They will usually then email you a response. Click the following link to report cyber harassment on Twitter: https://support.twitter.com/",
    textPK: "ٹویٹر پر رپورٹ کرنے کے چند ضوابط لاگو ہیں۔ فیس بک جیسے زیادہ تر سوشل میڈیا چینلز پر ان کے مواد کیساتھ ہی چند بٹن ہوتے ہیں۔ لیکن ان کے پاس الگ سے رپورٹ کرنے کی اقسام  بھی ہوتی ہیں جیسے دوہری شخصیتی اکاؤنٹ یا  ۔ پھر بعدازاں آپ کو ایک ای میل کے ذریعے جواب بھیج دیا جاتا ہے"
  },
  {
    titleEN: "Reporting Harassment on Instagram",
    titlePK: "انسٹا گرام پہ رپورٹ کرنا",
    textEN: "Like other social media accounts, Instagram profiles can also be attacked and hate accounts have been set up to target women in the past. Instagram has processes for reporting accounts and posts, and they can accept reports whether you have an account of your own or not. To keep yourself safe on Instagram report it on the following link: https://help.instagram.com/",
    textPK: "ماضی میں خواتین کو نشانہ بنانے کیلئے دیگر سوشل میڈیا اکاؤنٹس کی طرح انسٹا گرام پروفائلز پر بھی نفرت انگیز اور حملہ آور اکاؤنٹس ترتیب دیئے جا سکتے ہیں۔ اس زمرے میں انسٹا گرام پہ اکاؤنٹس اور پوسٹس کی  رپورٹ کرنے کیلئے ایک طریقہ کار مرتب ہے اور وہ آپ کی درج کی گئی رپورٹ کو وصول کرسکتے ہیں چاہے آپ کا اپنا اکاؤنٹ موجود ہو یا نہ ہو۔"
  },
  {
    titleEN: "Reporting Harassment on Snapchat",
    titlePK: "سنیپ چیٹ پہ رپورٹ کرنا",
    textEN: "The harassment may not be on the screen for long, but the distress can last a long time. To fight back, Snapchat offers a general reporting form that allows you to submit information about safety concerns. So if you’ve received a harassing image or message, an account is bullying you or you’ve been hacked, you can report it this way. Take a step and report cyber harassment on this link: https://support.snapchat.com/en-US/404",
    textPK: "اگرچہ ہراسانی کسی بھی سکرین پر بہت دیر تک نہیں رہ سکتی لیکن اس کے اثرات سے ہونے والی پریشانی تا دیر رہتی ہے۔ اس سے نبرد آزما ہونے کیلئے سنیپ چیٹ آپ کو ایک عمومی فارم تجویز کرتا ہے جو آپ کو دفاعی خدشات سے متعلق معلومات جمع کرنے کی اجازت دیتا ہے۔ لہٰذا اگر آپ کو کوئی ہراسانی سے بھرپور کوئی تصویر یا پیغام موصول ہوتا ہے، کسی اکاؤنٹ سے آپ کو تنگ کیا جاتاہے یا آپ کو ہیک کرلیا گیا ہے تو آپ اس طریقے سے رپورٹ کر سکتے ہیں۔"
  },
];

export {reportTo};
<|endoftext|>


<commit_before>/* ==========================================================
 * Tclock
 * date: Sep 4 2011
 * author: Yasuyuki Kozakai
 * last update: Sep 4 2011
 * web: nothing
 * Free to use under the BSD license.
 * ========================================================== */
(function($) {
	$.fn.tclock = function(options) {
		return this.each(function(){
			var target = $(this);
			var targetTime = target.find('.tclock-time');
			var targetDate = target.find('.tclock-date');

			var ticker = {
				start : function() {
					ticker.update();
					setInterval(ticker.update, 1000);
				},
				update : function() {
					function twoDigits(num) {
						return String("00" + num)
								.slice(-2);
					}

					var now     = new Date();
					var year    = now.getFullYear();
					var month   = now.getMonth();
					var date    = now.getDate();
					var day     = now.getDay();
					var hours   = now.getHours();
					var minutes = now.getMinutes();
					var seconds = now.getSeconds();

					var month_str = new Array(
						"Jan", "Feb", "Mar", "Apr",
						"May", "Jun", "Jul", "Aug",
						"Sep", "Oct", "Nov", "Dec");
					var week_str = new Array(
						"Sun", "Mon", "Tue", "Wed",
						"Thu", "Fri", "Sat");

					var time_str
						= twoDigits(hours) + ":" +
						  twoDigits(minutes) + ":" +
						  twoDigits(seconds);
					var date_str
						= week_str[day] + " " +
						  month_str[month] + " " +
						  twoDigits(date) + ", " +
						  year;

					targetTime.html(time_str);
					targetDate.html(date_str);
				}
			}

			ticker.start();
		})
	}
}(jQuery));
<commit_msg>Improves the white spaces in tclock.js<commit_after>/* ==========================================================
 * Tclock
 * date: Sep 4 2011
 * author: Yasuyuki Kozakai
 * last update: Sep 4 2011
 * web: nothing
 * Free to use under the BSD license.
 * ========================================================== */
(function($) {
$.fn.tclock = function(options) {
return this.each(function(){
	var target = $(this);
	var targetTime = target.find('.tclock-time');
	var targetDate = target.find('.tclock-date');

	var ticker = {
		start : function() {
			ticker.update();
			setInterval(ticker.update, 1000);
		},
		update : function() {
			function twoDigits(num) {
				return String("00" + num)
						.slice(-2);
			}

			var now     = new Date();
			var year    = now.getFullYear();
			var month   = now.getMonth();
			var date    = now.getDate();
			var day     = now.getDay();
			var hours   = now.getHours();
			var minutes = now.getMinutes();
			var seconds = now.getSeconds();

			var month_str = new Array(
				"Jan", "Feb", "Mar", "Apr", "May", "Jun",
				"Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
			var week_str = new Array(
				"Sun", "Mon", "Tue", "Wed",
				"Thu", "Fri", "Sat");

			var time_str = twoDigits(hours) + ":" +
				       twoDigits(minutes) + ":" +
				       twoDigits(seconds);

			var date_str = week_str[day] + " " +
				       month_str[month] + " " +
				       twoDigits(date) + ", " +
				       year;

			targetTime.html(time_str);
			targetDate.html(date_str);
		}
	}

	ticker.start();
})}}(jQuery));
<|endoftext|>


<commit_before>'use strict';

var d        = require('d/d')
  , callable = require('es5-ext/object/valid-callable')

  , apply = Function.prototype.apply, call = Function.prototype.call
  , create = Object.create, defineProperty = Object.defineProperty
  , defineProperties = Object.defineProperties
  , hasOwnProperty = Object.prototype.hasOwnProperty
  , descriptor = { configurable: true, enumerable: false, writable: true }

  , on, once, off, emit, methods, descriptors, base;

on = function (type, listener) {
	var data;

	callable(listener);

	if (!this.hasOwnProperty('__ee__')) {
		data = descriptor.value = create(null);
		defineProperty(this, '__ee__', descriptor);
		descriptor.value = null;
	} else {
		data = this.__ee__;
	}
	if (!hasOwnProperty.call(data, type)) data[type] = listener;
	else if (typeof data[type] === 'object') data[type].push(listener);
	else data[type] = [data[type], listener];

	return this;
};

once = function (type, listener) {
	var once, self;

	callable(listener);
	self = this;
	on.call(this, type, once = function () {
		off.call(self, type, once);
		apply.call(listener, this, arguments);
	});

	once._listener = listener;
	return this;
};

off = function (type, listener) {
	var data, listeners, candidate, i;

	callable(listener);

	if (!this.hasOwnProperty('__ee__')) return this;
	data = this.__ee__;
	if (!hasOwnProperty.call(data, type)) return this;
	listeners = data[type];

	if (typeof listeners === 'object') {
		for (i = 0; (candidate = listeners[i]); ++i) {
			if ((candidate === listener) || (candidate._listener === listener)) {
				if (listeners.length === 2) data[type] = listeners[i ? 0 : 1];
				else listeners.splice(i, 1);
			}
		}
	} else {
		if ((listeners === listener) || (listeners._listener === listener)) {
			delete data[type];
		}
	}

	return this;
};

emit = function (type) {
	var data, i, l, listener, listeners, args;

	if (!this.hasOwnProperty('__ee__')) return;
	data = this.__ee__;
	if (!hasOwnProperty.call(data, type)) return;
	listeners = data[type];

	if (typeof listeners === 'object') {
		l = arguments.length;
		args = new Array(l - 1);
		for (i = 1; i < l; ++i) {
			args[i - 1] = arguments[i];
		}

		listeners = listeners.slice();
		for (i = 0; (listener = listeners[i]); ++i) {
			apply.call(listener, this, args);
		}
	} else {
		switch (arguments.length) {
		case 1:
			call.call(listeners, this);
			break;
		case 2:
			call.call(listeners, this, arguments[1]);
			break;
		case 3:
			call.call(listeners, this, arguments[1], arguments[2]);
			break;
		default:
			l = arguments.length;
			args = new Array(l - 1);
			for (i = 1; i < l; ++i) {
				args[i - 1] = arguments[i];
			}
			apply.call(listeners, this, args);
		}
	}
};

methods = {
	on: on,
	once: once,
	off: off,
	emit: emit
};

descriptors = {
	on: d(on),
	once: d(once),
	off: d(off),
	emit: d(emit)
};

base = defineProperties({}, descriptors);

module.exports = exports = function (o) {
	return (o == null) ? create(base) : defineProperties(Object(o), descriptors);
};
exports.methods = methods;
<commit_msg>Use more unique once listener distinction<commit_after>'use strict';

var d        = require('d/d')
  , callable = require('es5-ext/object/valid-callable')

  , apply = Function.prototype.apply, call = Function.prototype.call
  , create = Object.create, defineProperty = Object.defineProperty
  , defineProperties = Object.defineProperties
  , hasOwnProperty = Object.prototype.hasOwnProperty
  , descriptor = { configurable: true, enumerable: false, writable: true }

  , on, once, off, emit, methods, descriptors, base;

on = function (type, listener) {
	var data;

	callable(listener);

	if (!this.hasOwnProperty('__ee__')) {
		data = descriptor.value = create(null);
		defineProperty(this, '__ee__', descriptor);
		descriptor.value = null;
	} else {
		data = this.__ee__;
	}
	if (!hasOwnProperty.call(data, type)) data[type] = listener;
	else if (typeof data[type] === 'object') data[type].push(listener);
	else data[type] = [data[type], listener];

	return this;
};

once = function (type, listener) {
	var once, self;

	callable(listener);
	self = this;
	on.call(this, type, once = function () {
		off.call(self, type, once);
		apply.call(listener, this, arguments);
	});

	once.__eeOnceListener__ = listener;
	return this;
};

off = function (type, listener) {
	var data, listeners, candidate, i;

	callable(listener);

	if (!this.hasOwnProperty('__ee__')) return this;
	data = this.__ee__;
	if (!hasOwnProperty.call(data, type)) return this;
	listeners = data[type];

	if (typeof listeners === 'object') {
		for (i = 0; (candidate = listeners[i]); ++i) {
			if ((candidate === listener) ||
					(candidate.__eeOnceListener__ === listener)) {
				if (listeners.length === 2) data[type] = listeners[i ? 0 : 1];
				else listeners.splice(i, 1);
			}
		}
	} else {
		if ((listeners === listener) ||
				(listeners.__eeOnceListener__ === listener)) {
			delete data[type];
		}
	}

	return this;
};

emit = function (type) {
	var data, i, l, listener, listeners, args;

	if (!this.hasOwnProperty('__ee__')) return;
	data = this.__ee__;
	if (!hasOwnProperty.call(data, type)) return;
	listeners = data[type];

	if (typeof listeners === 'object') {
		l = arguments.length;
		args = new Array(l - 1);
		for (i = 1; i < l; ++i) {
			args[i - 1] = arguments[i];
		}

		listeners = listeners.slice();
		for (i = 0; (listener = listeners[i]); ++i) {
			apply.call(listener, this, args);
		}
	} else {
		switch (arguments.length) {
		case 1:
			call.call(listeners, this);
			break;
		case 2:
			call.call(listeners, this, arguments[1]);
			break;
		case 3:
			call.call(listeners, this, arguments[1], arguments[2]);
			break;
		default:
			l = arguments.length;
			args = new Array(l - 1);
			for (i = 1; i < l; ++i) {
				args[i - 1] = arguments[i];
			}
			apply.call(listeners, this, args);
		}
	}
};

methods = {
	on: on,
	once: once,
	off: off,
	emit: emit
};

descriptors = {
	on: d(on),
	once: d(once),
	off: d(off),
	emit: d(emit)
};

base = defineProperties({}, descriptors);

module.exports = exports = function (o) {
	return (o == null) ? create(base) : defineProperties(Object(o), descriptors);
};
exports.methods = methods;
<|endoftext|>


<commit_before>
  /***
   * @package Core
   * @description Internal utility and common methods.
   ***/

  // A few optimizations for Google Closure Compiler will save us a couple kb in the release script.
  var object = Object, array = Array, regexp = RegExp, date = Date, string = String, number = Number, math = Math, Undefined;

  // Internal toString
  var internalToString = object.prototype.toString;

  // The global context
  var globalContext = typeof global !== 'undefined' ? global : this;

  // Type check methods need a way to be accessed dynamically outside global context.
  var typeChecks = {};

  // defineProperty exists in IE8 but will error when trying to define a property on
  // native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
  var definePropertySupport = object.defineProperty && object.defineProperties;

  // Class initializers and class helpers

  var ClassNames = 'Array,Boolean,Date,Function,Number,String,RegExp'.split(',');

  var isArray    = buildClassCheck(ClassNames[0]);
  var isBoolean  = buildClassCheck(ClassNames[1]);
  var isDate     = buildClassCheck(ClassNames[2]);
  var isNumber   = buildClassCheck(ClassNames[4]);
  var isString   = buildClassCheck(ClassNames[5]);
  var isRegExp   = buildClassCheck(ClassNames[6]);

  function isFunction(obj) {
    return typeof obj === 'function';
  }

  function buildClassCheck(name) {
    var type, fn;
    if(/String|Number|Boolean/.test(name)) {
      type = name.toLowerCase();
    }
    fn = (name === 'Array' && array.isArray) || function(obj, klass) {
      if(type && typeof obj === type) {
        return true;
      }
      klass = klass || className(obj);
      return klass === '[object '+name+']';
    }
    typeChecks[name] = fn;
    return fn;
  }

  function className(obj) {
    return internalToString.call(obj);
  }

  function initializeClasses() {
    initializeClass(object);
    iterateOverObject(ClassNames, function(i,name) {
      initializeClass(globalContext[name]);
    });
  }

  function initializeClass(klass) {
    if(klass['SugarMethods']) return;
    defineProperty(klass, 'SugarMethods', {});
    extend(klass, false, false, {
      'extend': function(methods, override, instance) {
        extend(klass, instance !== false, override, methods);
      },
      'sugarRestore': function() {
        return batchMethodExecute(klass, arguments, function(target, name, m) {
          defineProperty(target, name, m.method);
        });
      },
      'sugarRevert': function() {
        return batchMethodExecute(klass, arguments, function(target, name, m) {
          if(m.existed) {
            defineProperty(target, name, m.original);
          } else {
            delete target[name];
          }
        });
      }
    });
  }

  // Class extending methods

  function extend(klass, instance, override, methods) {
    var extendee = instance ? klass.prototype : klass;
    initializeClass(klass);
    iterateOverObject(methods, function(name, method) {
      var original = extendee[name];
      var existed  = hasOwnProperty(extendee, name);
      if(typeof override === 'function') {
        method = wrapNative(extendee[name], method, override);
      }
      if(override !== false || !extendee[name]) {
        defineProperty(extendee, name, method);
      }
      // If the method is internal to Sugar, then store a reference so it can be restored later.
      klass['SugarMethods'][name] = { instance: instance, method: method, original: original, existed: existed };
    });
  }

  function extendSimilar(klass, instance, override, set, fn) {
    var methods = {};
    set = isString(set) ? set.split(',') : set;
    set.forEach(function(name, i) {
      fn(methods, name, i);
    });
    extend(klass, instance, override, methods);
  }

  function batchMethodExecute(klass, args, fn) {
    var all = args.length === 0, methods = multiArgs(args), changed = false;
    iterateOverObject(klass['SugarMethods'], function(name, m) {
      if(all || methods.indexOf(name) !== -1) {
        changed = true;
        fn(m.instance ? klass.prototype : klass, name, m);
      }
    });
    return changed;
  }

  function wrapNative(nativeFn, extendedFn, condition) {
    return function() {
      var fn;
      if(nativeFn && (condition === true || !condition.apply(this, arguments))) {
        fn = nativeFn;
      } else {
        fn = extendedFn;
      }
      return fn.apply(this, arguments);
    }
  }

  function defineProperty(target, name, method) {
    if(definePropertySupport) {
      object.defineProperty(target, name, { 'value': method, 'configurable': true, 'enumerable': false, 'writable': true });
    } else {
      target[name] = method;
    }
  }

  // Argument helpers

  function multiArgs(args, fn) {
    var result = [], i, len;
    for(i = 0, len = args.length; i < len; i++) {
      result.push(args[i]);
      if(fn) fn.call(args, args[i], i);
    }
    return result;
  }

  function flattenedArgs(obj, fn, from) {
    multiArgs(array.prototype.concat.apply([], array.prototype.slice.call(obj, from || 0)), fn);
  }

  function checkCallback(fn) {
    if(!fn || !fn.call) {
      throw new TypeError('Callback is not callable');
    }
  }

  // General helpers

  function isDefined(o) {
    return o !== Undefined;
  }

  function isUndefined(o) {
    return o === Undefined;
  }

  // Object helpers

  function isObjectPrimitive(obj) {
    // Check for null
    return obj && typeof obj === 'object';
  }

  function isPlainObject(obj, klass) {
    klass = klass || className(obj);
    try {
      // Not own constructor property must be Object
      // This code was borrowed from jQuery.isPlainObject
      if (obj.constructor &&
            !hasOwnProperty(obj, 'constructor') &&
            !hasOwnProperty(obj.constructor.prototype, 'isPrototypeOf')) {
        return false;
      }
    } catch (e) {
      // IE8,9 Will throw exceptions on certain host objects.
      return false;
    }
    // === on the constructor is not safe across iframes
    // 'hasOwnProperty' ensures that the object also inherits
    // from Object, which is false for DOMElements in IE.
    return !!obj && klass === '[object Object]' && 'hasOwnProperty' in obj;
  }

  function hasOwnProperty(obj, key) {
    return object['hasOwnProperty'].call(obj, key);
  }

  function iterateOverObject(obj, fn) {
    var key;
    for(key in obj) {
      if(!hasOwnProperty(obj, key)) continue;
      if(fn.call(obj, key, obj[key], obj) === false) break;
    }
  }

  function simpleRepeat(n, fn) {
    for(var i = 0; i < n; i++) {
      fn(i);
    }
  }

  function simpleMerge(target, source) {
    iterateOverObject(source, function(key) {
      target[key] = source[key];
    });
    return target;
  }

  // Hash definition

  function Hash(obj) {
    simpleMerge(this, obj);
  };

  Hash.prototype.constructor = object;

  // Number helpers

  function round(val, precision, method) {
    var fn = math[method || 'round'];
    var multiplier = math.pow(10, math.abs(precision || 0));
    if(precision < 0) multiplier = 1 / multiplier;
    return fn(val * multiplier) / multiplier;
  }

  function ceil(val, precision) {
    return round(val, precision, 'ceil');
  }

  function floor(val, precision) {
    return round(val, precision, 'floor');
  }

  // Used by Number and Date

  function padNumber(num, place, sign, base) {
    var str = math.abs(num).toString(base || 10);
    str = repeatString(place - str.replace(/\.\d+/, '').length, '0') + str;
    if(sign || num < 0) {
      str = (num < 0 ? '-' : '+') + str;
    }
    return str;
  }

  function getOrdinalizedSuffix(num) {
    if(num >= 11 && num <= 13) {
      return 'th';
    } else {
      switch(num % 10) {
        case 1:  return 'st';
        case 2:  return 'nd';
        case 3:  return 'rd';
        default: return 'th';
      }
    }
  }

  // String helpers

  // WhiteSpace/LineTerminator as defined in ES5.1 plus Unicode characters in the Space, Separator category.
  function getTrimmableCharacters() {
    return '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF';
  }

  function repeatString(times, str) {
    return array(math.max(0, isDefined(times) ? times : 1) + 1).join(str || '');
  }

  // RegExp helpers

  function getRegExpFlags(reg, add) {
    var flags = reg.toString().match(/[^/]*$/)[0];
    if(add) {
      flags = (flags + add).split('').sort().join('').replace(/([gimy])\1+/g, '$1');
    }
    return flags;
  }

  function escapeRegExp(str) {
    if(!isString(str)) str = string(str);
    return str.replace(/([\\/'*+?|()\[\]{}.^$])/g,'\\$1');
  }

  // Date helpers

  function callDateGet(d, method) {
    return d['get' + (d._utc ? 'UTC' : '') + method]();
  }

  function callDateSet(d, method, value) {
    return d['set' + (d._utc && method != 'ISOWeek' ? 'UTC' : '') + method](value);
  }

  function extractDurationFromString(str) {
    var match, val, unit;
    match = str.toLowerCase().match(/^(\d+)?\s?(\w+?)s?$/i);
    val = parseInt(match[1]) || 1;
    unit = match[2].slice(0,1).toUpperCase() + match[2].slice(1);
    if(unit.match(/hour|minute|second/i)) {
      unit += 's';
    } else if(unit === 'Year') {
      unit = 'FullYear';
    } else if(unit === 'Day') {
      unit = 'Date';
    }
    return [val, unit];
  }

  // Specialized helpers

  // Used by Array#unique and Object.equal

  function stringify(thing, stack) {
    var type = typeof thing,
        thingIsObject,
        thingIsArray,
        klass, value,
        arr, key, i, len;

    // Return quickly if string to save cycles
    if(type === 'string') return thing;

    klass         = internalToString.call(thing)
    thingIsObject = isPlainObject(thing, klass);
    thingIsArray  = isArray(thing, klass);

    if(thing != null && thingIsObject || thingIsArray) {
      // This method for checking for cyclic structures was egregiously stolen from
      // the ingenious method by @kitcambridge from the Underscore script:
      // https://github.com/documentcloud/underscore/issues/240
      if(!stack) stack = [];
      // Allowing a step into the structure before triggering this
      // script to save cycles on standard JSON structures and also to
      // try as hard as possible to catch basic properties that may have
      // been modified.
      if(stack.length > 1) {
        i = stack.length;
        while (i--) {
          if (stack[i] === thing) {
            return 'CYC';
          }
        }
      }
      stack.push(thing);
      value = thing.valueOf() + string(thing.constructor);
      arr = thingIsArray ? thing : object.keys(thing).sort();
      for(i = 0, len = arr.length; i < len; i++) {
        key = thingIsArray ? i : arr[i];
        value += key + stringify(thing[key], stack);
      }
      stack.pop();
    } else if(1 / thing === -Infinity) {
      value = '-0';
    } else {
      value = string(thing && thing.valueOf ? thing.valueOf() : thing);
    }
    return type + klass + value;
  }

  function isEqual(a, b) {
    if(objectIsMatchedByValue(a) && objectIsMatchedByValue(b)) {
      return stringify(a) === stringify(b);
    } else {
      return a === b;
    }
  }

  function objectIsMatchedByValue(obj) {
    // Only known objects are matched by value. This is notably excluding functions, DOM Elements, and instances of
    // user-created classes. The latter can arguably be matched by value, but distinguishing between these and
    // host objects -- which should never be compared by value -- is very tricky so not dealing with it here.
    var klass = className(obj);
    return /^\[object Date|Array|String|Number|RegExp|Boolean|Arguments\]$/.test(klass) || isPlainObject(obj, klass);
  }

  // Used by Array#at and String#at

  function entryAtIndex(arr, args, str) {
    var result = [], length = arr.length, loop = args[args.length - 1] !== false, r;
    multiArgs(args, function(index) {
      if(isBoolean(index)) return false;
      if(loop) {
        index = index % length;
        if(index < 0) index = length + index;
      }
      r = str ? arr.charAt(index) || '' : arr[index];
      result.push(r);
    });
    return result.length < 2 ? result[0] : result;
  }

  // Object class methods implemented as instance methods

  function buildObjectInstanceMethods(set, target) {
    extendSimilar(target, true, false, set, function(methods, name) {
      methods[name + (name === 'equal' ? 's' : '')] = function() {
        return object[name].apply(null, [this].concat(multiArgs(arguments)));
      }
    });
  }

  initializeClasses();

<commit_msg>much faster repeat string<commit_after>
  /***
   * @package Core
   * @description Internal utility and common methods.
   ***/

  // A few optimizations for Google Closure Compiler will save us a couple kb in the release script.
  var object = Object, array = Array, regexp = RegExp, date = Date, string = String, number = Number, math = Math, Undefined;

  // Internal toString
  var internalToString = object.prototype.toString;

  // The global context
  var globalContext = typeof global !== 'undefined' ? global : this;

  // Type check methods need a way to be accessed dynamically outside global context.
  var typeChecks = {};

  // defineProperty exists in IE8 but will error when trying to define a property on
  // native objects. IE8 does not have defineProperies, however, so this check saves a try/catch block.
  var definePropertySupport = object.defineProperty && object.defineProperties;

  // Class initializers and class helpers

  var ClassNames = 'Array,Boolean,Date,Function,Number,String,RegExp'.split(',');

  var isArray    = buildClassCheck(ClassNames[0]);
  var isBoolean  = buildClassCheck(ClassNames[1]);
  var isDate     = buildClassCheck(ClassNames[2]);
  var isNumber   = buildClassCheck(ClassNames[4]);
  var isString   = buildClassCheck(ClassNames[5]);
  var isRegExp   = buildClassCheck(ClassNames[6]);

  function isFunction(obj) {
    return typeof obj === 'function';
  }

  function buildClassCheck(name) {
    var type, fn;
    if(/String|Number|Boolean/.test(name)) {
      type = name.toLowerCase();
    }
    fn = (name === 'Array' && array.isArray) || function(obj, klass) {
      if(type && typeof obj === type) {
        return true;
      }
      klass = klass || className(obj);
      return klass === '[object '+name+']';
    }
    typeChecks[name] = fn;
    return fn;
  }

  function className(obj) {
    return internalToString.call(obj);
  }

  function initializeClasses() {
    initializeClass(object);
    iterateOverObject(ClassNames, function(i,name) {
      initializeClass(globalContext[name]);
    });
  }

  function initializeClass(klass) {
    if(klass['SugarMethods']) return;
    defineProperty(klass, 'SugarMethods', {});
    extend(klass, false, false, {
      'extend': function(methods, override, instance) {
        extend(klass, instance !== false, override, methods);
      },
      'sugarRestore': function() {
        return batchMethodExecute(klass, arguments, function(target, name, m) {
          defineProperty(target, name, m.method);
        });
      },
      'sugarRevert': function() {
        return batchMethodExecute(klass, arguments, function(target, name, m) {
          if(m.existed) {
            defineProperty(target, name, m.original);
          } else {
            delete target[name];
          }
        });
      }
    });
  }

  // Class extending methods

  function extend(klass, instance, override, methods) {
    var extendee = instance ? klass.prototype : klass;
    initializeClass(klass);
    iterateOverObject(methods, function(name, method) {
      var original = extendee[name];
      var existed  = hasOwnProperty(extendee, name);
      if(typeof override === 'function') {
        method = wrapNative(extendee[name], method, override);
      }
      if(override !== false || !extendee[name]) {
        defineProperty(extendee, name, method);
      }
      // If the method is internal to Sugar, then store a reference so it can be restored later.
      klass['SugarMethods'][name] = { instance: instance, method: method, original: original, existed: existed };
    });
  }

  function extendSimilar(klass, instance, override, set, fn) {
    var methods = {};
    set = isString(set) ? set.split(',') : set;
    set.forEach(function(name, i) {
      fn(methods, name, i);
    });
    extend(klass, instance, override, methods);
  }

  function batchMethodExecute(klass, args, fn) {
    var all = args.length === 0, methods = multiArgs(args), changed = false;
    iterateOverObject(klass['SugarMethods'], function(name, m) {
      if(all || methods.indexOf(name) !== -1) {
        changed = true;
        fn(m.instance ? klass.prototype : klass, name, m);
      }
    });
    return changed;
  }

  function wrapNative(nativeFn, extendedFn, condition) {
    return function() {
      var fn;
      if(nativeFn && (condition === true || !condition.apply(this, arguments))) {
        fn = nativeFn;
      } else {
        fn = extendedFn;
      }
      return fn.apply(this, arguments);
    }
  }

  function defineProperty(target, name, method) {
    if(definePropertySupport) {
      object.defineProperty(target, name, { 'value': method, 'configurable': true, 'enumerable': false, 'writable': true });
    } else {
      target[name] = method;
    }
  }

  // Argument helpers

  function multiArgs(args, fn) {
    var result = [], i, len;
    for(i = 0, len = args.length; i < len; i++) {
      result.push(args[i]);
      if(fn) fn.call(args, args[i], i);
    }
    return result;
  }

  function flattenedArgs(obj, fn, from) {
    multiArgs(array.prototype.concat.apply([], array.prototype.slice.call(obj, from || 0)), fn);
  }

  function checkCallback(fn) {
    if(!fn || !fn.call) {
      throw new TypeError('Callback is not callable');
    }
  }

  // General helpers

  function isDefined(o) {
    return o !== Undefined;
  }

  function isUndefined(o) {
    return o === Undefined;
  }

  // Object helpers

  function isObjectPrimitive(obj) {
    // Check for null
    return obj && typeof obj === 'object';
  }

  function isPlainObject(obj, klass) {
    klass = klass || className(obj);
    try {
      // Not own constructor property must be Object
      // This code was borrowed from jQuery.isPlainObject
      if (obj.constructor &&
            !hasOwnProperty(obj, 'constructor') &&
            !hasOwnProperty(obj.constructor.prototype, 'isPrototypeOf')) {
        return false;
      }
    } catch (e) {
      // IE8,9 Will throw exceptions on certain host objects.
      return false;
    }
    // === on the constructor is not safe across iframes
    // 'hasOwnProperty' ensures that the object also inherits
    // from Object, which is false for DOMElements in IE.
    return !!obj && klass === '[object Object]' && 'hasOwnProperty' in obj;
  }

  function hasOwnProperty(obj, key) {
    return object['hasOwnProperty'].call(obj, key);
  }

  function iterateOverObject(obj, fn) {
    var key;
    for(key in obj) {
      if(!hasOwnProperty(obj, key)) continue;
      if(fn.call(obj, key, obj[key], obj) === false) break;
    }
  }

  function simpleRepeat(n, fn) {
    for(var i = 0; i < n; i++) {
      fn(i);
    }
  }

  function simpleMerge(target, source) {
    iterateOverObject(source, function(key) {
      target[key] = source[key];
    });
    return target;
  }

  // Hash definition

  function Hash(obj) {
    simpleMerge(this, obj);
  };

  Hash.prototype.constructor = object;

  // Number helpers

  function round(val, precision, method) {
    var fn = math[method || 'round'];
    var multiplier = math.pow(10, math.abs(precision || 0));
    if(precision < 0) multiplier = 1 / multiplier;
    return fn(val * multiplier) / multiplier;
  }

  function ceil(val, precision) {
    return round(val, precision, 'ceil');
  }

  function floor(val, precision) {
    return round(val, precision, 'floor');
  }

  // Used by Number and Date

  function padNumber(num, place, sign, base) {
    var str = math.abs(num).toString(base || 10);
    str = repeatString(place - str.replace(/\.\d+/, '').length, '0') + str;
    if(sign || num < 0) {
      str = (num < 0 ? '-' : '+') + str;
    }
    return str;
  }

  function getOrdinalizedSuffix(num) {
    if(num >= 11 && num <= 13) {
      return 'th';
    } else {
      switch(num % 10) {
        case 1:  return 'st';
        case 2:  return 'nd';
        case 3:  return 'rd';
        default: return 'th';
      }
    }
  }

  // String helpers

  // WhiteSpace/LineTerminator as defined in ES5.1 plus Unicode characters in the Space, Separator category.
  function getTrimmableCharacters() {
    return '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF';
  }

  function repeatString(times, str) {
    var result = '';
    if(isUndefined(times)) {
      times = 1;
    }
    while(times-- > 0) {
      result += str;
    }
    return result;
  }

  // RegExp helpers

  function getRegExpFlags(reg, add) {
    var flags = reg.toString().match(/[^/]*$/)[0];
    if(add) {
      flags = (flags + add).split('').sort().join('').replace(/([gimy])\1+/g, '$1');
    }
    return flags;
  }

  function escapeRegExp(str) {
    if(!isString(str)) str = string(str);
    return str.replace(/([\\/'*+?|()\[\]{}.^$])/g,'\\$1');
  }

  // Date helpers

  function callDateGet(d, method) {
    return d['get' + (d._utc ? 'UTC' : '') + method]();
  }

  function callDateSet(d, method, value) {
    return d['set' + (d._utc && method != 'ISOWeek' ? 'UTC' : '') + method](value);
  }

  function extractDurationFromString(str) {
    var match, val, unit;
    match = str.toLowerCase().match(/^(\d+)?\s?(\w+?)s?$/i);
    val = parseInt(match[1]) || 1;
    unit = match[2].slice(0,1).toUpperCase() + match[2].slice(1);
    if(unit.match(/hour|minute|second/i)) {
      unit += 's';
    } else if(unit === 'Year') {
      unit = 'FullYear';
    } else if(unit === 'Day') {
      unit = 'Date';
    }
    return [val, unit];
  }

  // Specialized helpers

  // Used by Array#unique and Object.equal

  function stringify(thing, stack) {
    var type = typeof thing,
        thingIsObject,
        thingIsArray,
        klass, value,
        arr, key, i, len;

    // Return quickly if string to save cycles
    if(type === 'string') return thing;

    klass         = internalToString.call(thing)
    thingIsObject = isPlainObject(thing, klass);
    thingIsArray  = isArray(thing, klass);

    if(thing != null && thingIsObject || thingIsArray) {
      // This method for checking for cyclic structures was egregiously stolen from
      // the ingenious method by @kitcambridge from the Underscore script:
      // https://github.com/documentcloud/underscore/issues/240
      if(!stack) stack = [];
      // Allowing a step into the structure before triggering this
      // script to save cycles on standard JSON structures and also to
      // try as hard as possible to catch basic properties that may have
      // been modified.
      if(stack.length > 1) {
        i = stack.length;
        while (i--) {
          if (stack[i] === thing) {
            return 'CYC';
          }
        }
      }
      stack.push(thing);
      value = thing.valueOf() + string(thing.constructor);
      arr = thingIsArray ? thing : object.keys(thing).sort();
      for(i = 0, len = arr.length; i < len; i++) {
        key = thingIsArray ? i : arr[i];
        value += key + stringify(thing[key], stack);
      }
      stack.pop();
    } else if(1 / thing === -Infinity) {
      value = '-0';
    } else {
      value = string(thing && thing.valueOf ? thing.valueOf() : thing);
    }
    return type + klass + value;
  }

  function isEqual(a, b) {
    if(objectIsMatchedByValue(a) && objectIsMatchedByValue(b)) {
      return stringify(a) === stringify(b);
    } else {
      return a === b;
    }
  }

  function objectIsMatchedByValue(obj) {
    // Only known objects are matched by value. This is notably excluding functions, DOM Elements, and instances of
    // user-created classes. The latter can arguably be matched by value, but distinguishing between these and
    // host objects -- which should never be compared by value -- is very tricky so not dealing with it here.
    var klass = className(obj);
    return /^\[object Date|Array|String|Number|RegExp|Boolean|Arguments\]$/.test(klass) || isPlainObject(obj, klass);
  }

  // Used by Array#at and String#at

  function entryAtIndex(arr, args, str) {
    var result = [], length = arr.length, loop = args[args.length - 1] !== false, r;
    multiArgs(args, function(index) {
      if(isBoolean(index)) return false;
      if(loop) {
        index = index % length;
        if(index < 0) index = length + index;
      }
      r = str ? arr.charAt(index) || '' : arr[index];
      result.push(r);
    });
    return result.length < 2 ? result[0] : result;
  }

  // Object class methods implemented as instance methods

  function buildObjectInstanceMethods(set, target) {
    extendSimilar(target, true, false, set, function(methods, name) {
      methods[name + (name === 'equal' ? 's' : '')] = function() {
        return object[name].apply(null, [this].concat(multiArgs(arguments)));
      }
    });
  }

  initializeClasses();

<|endoftext|>