<commit_before>var assert = require("assert");
var path = require("path");
var fs = require("fs");
var hasOwn = Object.hasOwnProperty;
var defaultHandler = require.extensions[".js"];
var convertSourceMap = require("convert-source-map");
var meteorBabel = require("./index.js");
var util = require("./util.js");

require("reify/node/runtime");

var config = {
  sourceMapRootPath: null,
  allowedDirectories: Object.create(null),
  babelOptions: require("./options").getDefaults()
};

exports.setSourceMapRootPath = function (smrp) {
  config.sourceMapRootPath = smrp;
  return exports;
};

exports.allowDirectory = function (dir) {
  config.allowedDirectories[dir] = true;
  return exports;
};

exports.setBabelOptions = function (options) {
  config.babelOptions = options;
  return exports;
};

require.extensions[".js"] = function(module, filename) {
  if (shouldNotTransform(filename)) {
    defaultHandler(module, filename);
  } else {
    module._compile(
      getBabelResult(filename).code,
      filename
    );
  }
};

exports.retrieveSourceMap = function(filename) {
  if (shouldNotTransform(filename)) {
    return null;
  }

  var result = getBabelResult(filename);
  var converted = result && convertSourceMap.fromSource(result.code);
  var map = converted && converted.toJSON();

  return map && {
    url: map.file,
    map: map
  } || null;
};

function shouldNotTransform(filename) {
  if (path.resolve(filename) !==
      path.normalize(filename)) {
    // If the filename is not absolute, then it's a file in a core Node
    // module, and should not be transformed.
    return true;
  }

  var dirs = Object.keys(config.allowedDirectories);
  var allowed = dirs.some(function (dir) {
    var relPath = path.relative(dir, filename);
    if (relPath.slice(0, 2) === "..") {
      // Ignore files that are not contained by an allowed directory.
      return false;
    }

    if (relPath.split(path.sep).indexOf("node_modules") >= 0) {
      // Ignore files that are contained by a node_modules directory that
      // is itself contained by the allowed dir.
      return false;
    }

    return true;
  });

  return ! allowed;
}

function getBabelResult(filename) {
  var source = fs.readFileSync(filename, "utf8");

  var babelOptions = {};
  for (var key in config.babelOptions) {
    if (hasOwn.call(config.babelOptions, key)) {
      babelOptions[key] = config.babelOptions[key];
    }
  }

  if (babelOptions.sourceMap) {
    if (config.sourceMapRootPath) {
      var relativePath = path.relative(
        config.sourceMapRootPath,
        filename
      );

      if (relativePath.slice(0, 2) !== "..") {
        // If the given filename is a path contained within
        // config.sourceMapRootPath, use the relative path but prepend a
        // '/' so that source maps work more reliably.
        filename = "/" + relativePath;
      }
    }

    babelOptions.filename = filename;
    babelOptions.sourceFileName = filename;
    babelOptions.sourceMapTarget = filename + ".map";
  }

  return meteorBabel.compile(source, babelOptions);
}
<commit_msg>Tolerate allowed paths that contain symlinks in register.js.<commit_after>var assert = require("assert");
var path = require("path");
var fs = require("fs");
var hasOwn = Object.hasOwnProperty;
var defaultHandler = require.extensions[".js"];
var convertSourceMap = require("convert-source-map");
var meteorBabel = require("./index.js");
var util = require("./util.js");

require("reify/node/runtime");

var config = {
  sourceMapRootPath: null,
  allowedDirectories: Object.create(null),
  babelOptions: require("./options").getDefaults()
};

exports.setSourceMapRootPath = function (smrp) {
  config.sourceMapRootPath = smrp;
  return exports;
};

exports.allowDirectory = function (dir) {
  config.allowedDirectories[dir] = true;
  // Sometimes the filename passed to the require.extensions handler is a
  // real path, and thus may not appear to be contained by an allowed
  // directory, even though it should be.
  config.allowedDirectories[fs.realpathSync(dir)] = true;
  return exports;
};

exports.setBabelOptions = function (options) {
  config.babelOptions = options;
  return exports;
};

require.extensions[".js"] = function(module, filename) {
  if (shouldNotTransform(filename)) {
    defaultHandler(module, filename);
  } else {
    module._compile(
      getBabelResult(filename).code,
      filename
    );
  }
};

exports.retrieveSourceMap = function(filename) {
  if (shouldNotTransform(filename)) {
    return null;
  }

  var result = getBabelResult(filename);
  var converted = result && convertSourceMap.fromSource(result.code);
  var map = converted && converted.toJSON();

  return map && {
    url: map.file,
    map: map
  } || null;
};

function shouldNotTransform(filename) {
  if (path.resolve(filename) !==
      path.normalize(filename)) {
    // If the filename is not absolute, then it's a file in a core Node
    // module, and should not be transformed.
    return true;
  }

  var dirs = Object.keys(config.allowedDirectories);
  var allowed = dirs.some(function (dir) {
    var relPath = path.relative(dir, filename);
    if (relPath.slice(0, 2) === "..") {
      // Ignore files that are not contained by an allowed directory.
      return false;
    }

    if (relPath.split(path.sep).indexOf("node_modules") >= 0) {
      // Ignore files that are contained by a node_modules directory that
      // is itself contained by the allowed dir.
      return false;
    }

    return true;
  });

  return ! allowed;
}

function getBabelResult(filename) {
  var source = fs.readFileSync(filename, "utf8");

  var babelOptions = {};
  for (var key in config.babelOptions) {
    if (hasOwn.call(config.babelOptions, key)) {
      babelOptions[key] = config.babelOptions[key];
    }
  }

  if (babelOptions.sourceMap) {
    if (config.sourceMapRootPath) {
      var relativePath = path.relative(
        config.sourceMapRootPath,
        filename
      );

      if (relativePath.slice(0, 2) !== "..") {
        // If the given filename is a path contained within
        // config.sourceMapRootPath, use the relative path but prepend a
        // '/' so that source maps work more reliably.
        filename = "/" + relativePath;
      }
    }

    babelOptions.filename = filename;
    babelOptions.sourceFileName = filename;
    babelOptions.sourceMapTarget = filename + ".map";
  }

  return meteorBabel.compile(source, babelOptions);
}
<|endoftext|>


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

(function () {

  // TODO(felix8a): these lists can get out of sync with reality

  // List of [testfile, mode].
  // If mode is omitted, both es5 and es53 are emitted.
  var test_cases = [
    ['es53-test-basic-functions-guest.html'],
    ['es53-test-domado-canvas-guest.html'],
    ['es53-test-domado-dom-guest.html'],
    ['es53-test-domado-forms-guest.html'],
    ['es53-test-inline-script.html'],
    ['es53-test-external-script-guest.html', 'es5'],
    ['es53-test-language-guest.html'],
    ['es53-test-precajole-guest.html', 'es53']
  ];

  var test_drivers = [
    ['es53-test-apitaming.js'],
    ['es53-test-automode-1.js'],
    ['es53-test-automode-2.js'],
    ['es53-test-automode-3.js'],
    ['es53-test-automode-4.js'],
    ['es53-test-cajajs-invocation.js'],
    ['es53-test-cajajs-minor-version-skew-cajoler-response.js'
     + '&cajajs=/caja/testing/skew-mmm/caja.js', 'es53'],
    ['es53-test-cajajs-never-starts.js'
     + '&cajajs=/caja/testing/skew-0000/caja.js'],
    ['es53-test-cajajs-never-starts.js'
     + '&resources=/caja/testing/nonexistent'],
    ['es53-test-cajajs-never-starts.js'
     + '&resources=/caja/testing/skew-0000'],
    ['es53-test-cajajs-version-skew-cajoled-module.js', 'es53'],
    ['es53-test-cajajs-version-skew-cajoler-response.js'
     + '&cajajs=/caja/testing/skew-0000/caja.js', 'es53'],
    ['es53-test-cajajs-version-skew-js-files.js'],
    ['es53-test-client-uri-rewriting.js'],
    ['es53-test-container-overflow.js'],
    ['es53-test-defensible-objects.js'],
    ['es53-test-domado-global.js'],
    ['es53-test-domado-events.js'],
    ['es53-test-domado-foreign.js'],
    ['es53-test-domado-special.js'],
    ['es53-test-proxies.js', 'es53'],
    ['es53-test-relative-urls.js'],
    ['es53-test-taming-errors.js'],
    ['es53-test-taming-inout.js'],
    ['es53-test-taming-primitives.js'],
    ['es53-test-taming-tamed.js'],
    ['es53-test-taming-untamed.js'],
    ['es53-test-unicode.js']
  ];

  var bare_tests = [
    'modules-test.html',
  ];

  var headless_rhino_tests = [
    'csslexer-test.html',
    'cssparser_test.html',
    'css-stylesheet-test.html',
    'html-emitter-test.html',
    'html-sanitizer-test.html',
    'html-sanitizer-minified-test.html',
    'html-sanitizer-regress.html',
    'html-css-sanitizer-test.html',
    'html-css-sanitizer-minified-test.html',
    'sanitizecss_test.html',
    'uri_test.html',
  ];

  var jquery = [
    'core',
    'callbacks',
    'deferred',
    'support',
    'data',
    'queue',
    'attributes',
    'event',
    'selector',
    'traversing',
    'manipulation',
    'css',
    'ajax',
    'effects',
    'offset',
    'dimensions',
    'exports'
  ];

  var jqueryui = [
    'accordion',
    'autocomplete',
    'button',
    'core',
    'datepicker',
    'dialog',
    'effects',
    'menu',
    'position',
    'progressbar',
    'slider',
    'spinner',
    'tabs',
    'tooltip',
    'widget'
  ];

  var tests_ul = document.getElementById('tests');

  function addSeparator() {
    tests_ul.appendChild(document.createElement('br'));
  }

  function addItem(html) {
    var li = document.createElement('li');
    li.innerHTML = html;
    tests_ul.appendChild(li);
  }

  function addBare(url, text) {
    addItem('' + (text || url) + '');
  }

  function addModed(url, text, mode, minify) {
    var html = '';
    if (!mode || mode === 'es53') {
      html += '[es53 ';
      html += 'min] ';
    } else {
      html += '[<s>es53</s> <s>min</s>] ';
    }
    if (!mode || mode === 'es5') {
      html += '[es5 ';
      html += 'min] ';
    } else {
      html += '[<s>es5</s> <s>min</s>] ';
    }
    html += text || url;
    addItem(html);
  }

  function addQUnit(text, rawUrl) {
    addModed('browser-test-case.html?jQuery=true&test-case=' + rawUrl, text,
        'es5');
  }

  function forEach(array, callback) {
    for (var i = 0; i < array.length; i++) {
      callback(array[i]);
    }
  }

  forEach(headless_rhino_tests, addBare);

  addSeparator();

  forEach(bare_tests, addBare);

  addSeparator();

  forEach(test_cases, function(item) {
    addModed('browser-test-case.html?test-case=' + item[0], item[0], item[1]);
  });

  addSeparator();

  forEach(test_drivers, function(item) {
    addModed('browser-test-case.html?test-driver=' + item[0], item[0], item[1]);
  });

  addSeparator()

  addModed('cajajs-bare-test.html?', 'cajajs-bare-test.html', null);

  addSeparator();

  forEach(jquery, function(test) {
    addQUnit('jQuery ' + test,
             '/ant-lib/js/jqueryjs/test/' + test + '-uncajoled.html');
  })

  forEach(jqueryui, function(test) {
    addQUnit('jQuery UI ' + test,
             '/third_party/js/jquery-ui/tests/unit/' + test + '/' + test +
                 '.html');
  })

})();
<commit_msg>Add "uncajoled" links to test-index where applicable. https://codereview.appspot.com/7052043<commit_after>// Copyright (C) 2012 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

(function () {

  // TODO(felix8a): these lists can get out of sync with reality

  // List of [testfile, mode].
  // If mode is omitted, both es5 and es53 are emitted.
  var test_cases = [
    ['es53-test-basic-functions-guest.html'],
    ['es53-test-domado-canvas-guest.html'],
    ['es53-test-domado-dom-guest.html'],
    ['es53-test-domado-forms-guest.html'],
    ['es53-test-inline-script.html'],
    ['es53-test-external-script-guest.html', 'es5'],
    ['es53-test-language-guest.html'],
    ['es53-test-precajole-guest.html', 'es53']
  ];

  var test_drivers = [
    ['es53-test-apitaming.js'],
    ['es53-test-automode-1.js'],
    ['es53-test-automode-2.js'],
    ['es53-test-automode-3.js'],
    ['es53-test-automode-4.js'],
    ['es53-test-cajajs-invocation.js'],
    ['es53-test-cajajs-minor-version-skew-cajoler-response.js'
     + '&cajajs=/caja/testing/skew-mmm/caja.js', 'es53'],
    ['es53-test-cajajs-never-starts.js'
     + '&cajajs=/caja/testing/skew-0000/caja.js'],
    ['es53-test-cajajs-never-starts.js'
     + '&resources=/caja/testing/nonexistent'],
    ['es53-test-cajajs-never-starts.js'
     + '&resources=/caja/testing/skew-0000'],
    ['es53-test-cajajs-version-skew-cajoled-module.js', 'es53'],
    ['es53-test-cajajs-version-skew-cajoler-response.js'
     + '&cajajs=/caja/testing/skew-0000/caja.js', 'es53'],
    ['es53-test-cajajs-version-skew-js-files.js'],
    ['es53-test-client-uri-rewriting.js'],
    ['es53-test-container-overflow.js'],
    ['es53-test-defensible-objects.js'],
    ['es53-test-domado-global.js'],
    ['es53-test-domado-events.js'],
    ['es53-test-domado-foreign.js'],
    ['es53-test-domado-special.js'],
    ['es53-test-proxies.js', 'es53'],
    ['es53-test-relative-urls.js'],
    ['es53-test-taming-errors.js'],
    ['es53-test-taming-inout.js'],
    ['es53-test-taming-primitives.js'],
    ['es53-test-taming-tamed.js'],
    ['es53-test-taming-untamed.js'],
    ['es53-test-unicode.js']
  ];

  var bare_tests = [
    'modules-test.html',
  ];

  var headless_rhino_tests = [
    'csslexer-test.html',
    'cssparser_test.html',
    'css-stylesheet-test.html',
    'html-emitter-test.html',
    'html-sanitizer-test.html',
    'html-sanitizer-minified-test.html',
    'html-sanitizer-regress.html',
    'html-css-sanitizer-test.html',
    'html-css-sanitizer-minified-test.html',
    'sanitizecss_test.html',
    'uri_test.html',
  ];

  var jquery = [
    'core',
    'callbacks',
    'deferred',
    'support',
    'data',
    'queue',
    'attributes',
    'event',
    'selector',
    'traversing',
    'manipulation',
    'css',
    'ajax',
    'effects',
    'offset',
    'dimensions',
    'exports'
  ];

  var jqueryui = [
    'accordion',
    'autocomplete',
    'button',
    'core',
    'datepicker',
    'dialog',
    'effects',
    'menu',
    'position',
    'progressbar',
    'slider',
    'spinner',
    'tabs',
    'tooltip',
    'widget'
  ];

  var tests_ul = document.getElementById('tests');

  function addSeparator() {
    tests_ul.appendChild(document.createElement('br'));
  }

  function addItem(html) {
    var li = document.createElement('li');
    li.innerHTML = html;
    tests_ul.appendChild(li);
  }

  function addBare(url, text) {
    addItem('' + (text || url) + '');
  }

  function addModed(url, text, mode, uncajoled) {
    var html = '';
    if (!mode || mode === 'es53') {
      html += '[es53 ';
      html += 'min] ';
    } else {
      html += '[<s>es53</s> <s>min</s>] ';
    }
    if (!mode || mode === 'es5') {
      html += '[es5 ';
      html += 'min] ';
    } else {
      html += '[<s>es5</s> <s>min</s>] ';
    }
    if (uncajoled) {
      html += '[uncajoled] ';
    }
    html += text || url;
    addItem(html);
  }

  function addQUnit(text, rawUrl) {
    addModed('browser-test-case.html?jQuery=true&test-case=' + rawUrl, text,
        'es5', rawUrl);
  }

  function forEach(array, callback) {
    for (var i = 0; i < array.length; i++) {
      callback(array[i]);
    }
  }

  forEach(headless_rhino_tests, addBare);

  addSeparator();

  forEach(bare_tests, addBare);

  addSeparator();

  forEach(test_cases, function(item) {
    addModed('browser-test-case.html?test-case=' + item[0], item[0], item[1]);
  });

  addSeparator();

  forEach(test_drivers, function(item) {
    addModed('browser-test-case.html?test-driver=' + item[0], item[0], item[1]);
  });

  addSeparator()

  addModed('cajajs-bare-test.html?', 'cajajs-bare-test.html', null);

  addSeparator();

  forEach(jquery, function(test) {
    addQUnit('jQuery ' + test,
             '/ant-lib/js/jqueryjs/test/' + test + '-uncajoled.html');
  })

  forEach(jqueryui, function(test) {
    addQUnit('jQuery UI ' + test,
             '/third_party/js/jquery-ui/tests/unit/' + test + '/' + test +
                 '.html');
  })

})();
<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Controller.extend({

    init: function() {
        this._super.apply(this, arguments);

        setTimeout(function(){
            this.set('functionBindWorks', true);
        }.bind(this), 1000);
    },

    functionBindWorks: false,

    browser: Ember.inject.service(),

    detect: function() {
        return this.get('browser').detect();
    }.property(),

    agent: function() {
        return this.get('browser').agent();
    }.property(),

    version: function() {
        return this.get('browser').version();
    }.property()

});
<commit_msg>Use Ember.computed instead of .property()<commit_after>import Ember from 'ember';
var computed = Ember.computed;

export default Ember.Controller.extend({
  browser: Ember.inject.service(),
  functionBindWorks: false,

  init: function() {
    this._super.apply(this, arguments);

    setTimeout(function() {
      this.set('functionBindWorks', true);
    }.bind(this), 1000);
  },

  detect: computed(function(){
    return this.get('browser').detect();
  }),

  agent: computed(function(){
    return this.get('browser').agent();
  }),

  version: computed(function(){
    return this.get('browser').version();
  })
});
<|endoftext|>


<commit_before>self.deprecationWorkflow = self.deprecationWorkflow || {};
self.deprecationWorkflow.config = {
  workflow: [
    { handler: "silence", matchId: "ember-views.curly-components.jquery-element" },
    { handler: "silence", matchId: "computed-property.override" }
  ]
};
<commit_msg>Fix eslint error<commit_after>/*global self*/
self.deprecationWorkflow = self.deprecationWorkflow || {};
self.deprecationWorkflow.config = {
  workflow: [
    { handler: "silence", matchId: "ember-views.curly-components.jquery-element" },
    { handler: "silence", matchId: "computed-property.override" }
  ]
};
<|endoftext|>


<commit_before>/*
 * This is a basic func test for a Common application.
 */
YUI.add('common-testlazyloadrpcclient-tests', function (Y) {

    var suite = new Y.Test.Suite("Common: LazyLoadRPCClient");

    suite.add(new Y.Test.Case({

        "test LazyLoadRPCClient": function() {
            var that = this;
            Y.one('#lazyloadrpcButton').simulate('click');
            that.wait(function(){
                Y.Assert.areEqual('lazy load succeeded: mydatavalue', Y.one('#LazyLoadRPCResult').get('innerHTML'));
            }, 2000);
        }

    }));
    Y.Test.Runner.add(suite);

}, '0.0.1', { requires: [
    'node', 'node-event-simulate', 'test', 'console'
]});

<commit_msg>add more test scenarios basing on review feedback<commit_after>/*
 * This is a basic func test for a Common application.
 */
YUI.add('common-testlazyloadrpcclient-tests', function (Y) {

    var suite = new Y.Test.Suite("Common: LazyLoadRPCClient");

    suite.add(new Y.Test.Case({

        "test LazyLoadRPCClient": function() {
            var that = this;
            Y.one('#lazyloadrpcButton').simulate('click');
            that.wait(function(){
                Y.Assert.areEqual('Lazy load succeeded:', Y.one('#LazyLoadRPCtitle').get('innerHTML'));
                Y.Assert.areEqual('foo-value set by binder', Y.one('#LazyLoadRPCfoo').get('innerHTML'));
                Y.Assert.areEqual('bar-value set by controller', Y.one('#LazyLoadRPCbar').get('innerHTML'));
                Y.Assert.areEqual('From controller: foo-value set by binder', Y.one('#LazyLoadRPCbaz').get('innerHTML'));
                Y.Assert.areEqual('Data has changed: 2 times', Y.one('#LazyLoadRPCcount').get('innerHTML'));
            }, 2000);
        }

    }));
    Y.Test.Runner.add(suite);

}, '0.0.1', { requires: [
    'node', 'node-event-simulate', 'test', 'console'
]});

<|endoftext|>


<commit_before>describe("ilios_utilities", function() {
  it("should create a utilities namespace on the ilios global object", function () {
    expect(typeof ilios.utilities).toBe("object");
  });

  it("should define 3 different user name formats", function () {
    var formats = [
      ilios.utilities.USER_NAME_FORMAT_LAST_FIRST,
      ilios.utilities.USER_NAME_FORMAT_FIRST_FIRST,
      ilios.utilities.USER_NAME_FORMAT_FIRST_INITIAL_FIRST
    ];
    expect(formats[0]).toBeDefined();
    expect(formats[1]).toBeDefined();
    expect(formats[2]).toBeDefined();
    expect(formats[0]).not.toEqual(formats[1]);
    expect(formats[0]).not.toEqual(formats[2]);
    expect(formats[1]).not.toEqual(formats[2]);
  });

  describe("setToolTipForElement()", function () {
    it("should set the title attribute of the element", function () {
      var element = document.createElement('div');
      var tooltip = "Should tooltip text really go in the title attribute?";
      ilios.utilities.setToolTipForElement(element, tooltip);
      expect(element.getAttribute('title')).toBe(tooltip);
    });
  });

  describe("getEventTarget()", function () {
    var event;
    var div;

    beforeEach(function () {
      // Don't use real events. Let those get found in integration tests.
      // Just use a simple object for testing instead. We're just testing
      // the logic in the method, not browser quirks, etc.
      event = {};
      div = document.createElement('div');
    });

    it("should return target attribute if it exists", function () {
      event.target = div;
      expect(ilios.utilities.getEventTarget(event)).toEqual(div);
    });

    it("should return srcElement attribute if target attribute does not exist", function () {
      event.srcElement = div;
      expect(ilios.utilities.getEventTarget(event)).toEqual(div);
    });
  });

  describe("getParsedResponseObjectFromFormUploadResponseText()", function () {
    it("should strip off leading and trailing
 tags", function () {
      var responseText = "
{\"foo\": \"bar\"}
";
      var parsed = ilios.utilities.getParsedResponseObjectFromFormUploadResponseText(responseText);
      expect(parsed).toEqual({foo: "bar"});
    });

    it("should strip off leading and trailing
 tags", function () {
      var responseText = "
{\"foo\": \"bar\"}
";
      var parsed = ilios.utilities.getParsedResponseObjectFromFormUploadResponseText(responseText);
      expect(parsed).toEqual({foo: "bar"});
    });

    it("should handle the string if there are no pre elements", function () {
      var responseText = "{\"foo\": \"bar\"}";
      var parsed = ilios.utilities.getParsedResponseObjectFromFormUploadResponseText(responseText);
      expect(parsed).toEqual({foo: "bar"});
    });

    it("should call ilios.global.defaultAJAXFailureHandler and return null if JSON is invalid", function () {
      var responseText = "invalid JSON!";
      spyOn(ilios.global, "defaultAJAXFailureHandler");
      var parsed = ilios.utilities.getParsedResponseObjectFromFormUploadResponseText(responseText);
      expect(ilios.global.defaultAJAXFailureHandler).toHaveBeenCalled();
      expect(parsed).toBe(null);
    });

    it("should not call ilios.global.defaultAJAXFailureHandler if JSON is valid", function () {
      var responseText = "{\"foo\": \"bar\"}";
      spyOn(ilios.global, "defaultAJAXFailureHandler");
      ilios.utilities.getParsedResponseObjectFromFormUploadResponseText(responseText);
      expect(ilios.global.defaultAJAXFailureHandler).not.toHaveBeenCalled();
    });
  });

  describe("dateObjectToMySQLFriendly()", function () {
    var utcDate = new Date("2010-06-28 15:26:02 UTC");
    var pdtDate = new Date("2010-06-28 15:26:02 PDT");

    it("should return MySQL-formatted date string for date object", function () {
      var mysqlFriendly = ilios.utilities.dateObjectToMySQLFriendly(utcDate);
      expect(mysqlFriendly).toBe("2010-06-28");
    });

    it("should return date but not time if includeTime is false", function () {
      var mysqlFriendly = ilios.utilities.dateObjectToMySQLFriendly(utcDate, false);
      expect(mysqlFriendly).toBe("2010-06-28");
    });

    it("should return the date and time if includeTime is true", function () {
      var mysqlFriendly = ilios.utilities.dateObjectToMySQLFriendly(utcDate, true);
      expect(mysqlFriendly).toBe("2010-06-28 15:26:02");
    });

    it("should convert time to UTC", function () {
      var mysqlFriendly = ilios.utilities.dateObjectToMySQLFriendly(pdtDate, true);
      expect(mysqlFriendly).toBe("2010-06-28 22:26:02");
    });
  });

  describe("mySQLTimelessDateToDateObject()", function () {
    it("should return a Date object for midnight local time of the yyyyMMDDStr", function () {
      var mySqlTime = ilios.utilities.mySQLTimelessDateToDateObject("2010-06-28");
      expect(mySqlTime).toEqual(new Date("2010-06-28 00:00:00"));
    });
  });

  describe("mySQLDateToDateObject()", function () {
    it("should work with a two-digit year", function () {
      // Current implementation requires a trailing space. Bug?
      // Current implementation accepts a two-digit year, but treats it like a two-digit year. 10 = 10 AD. Bug?
      // I'm guessing two-digit years and date-only (no time) just simply really aren't supported.
      var mySQLDateString = "10-06-28 ";
      var DateObject = ilios.utilities.mySQLDateToDateObject(mySQLDateString);
      var expected = new Date("June 28");
      expected.setFullYear(10);
      expect(DateObject).toEqual(expected);
    });

    it("should work without a timestamp", function () {
      // Current implementation requires a trailing space. Bug?
      var mySQLDateString = "2010-06-28 ";
      var DateObject = ilios.utilities.mySQLDateToDateObject(mySQLDateString);
      var expected = new Date("June 28, 2010");
      expect(DateObject).toEqual(expected);
    });

    it("should work with a timestamp", function () {
      var mySQLDateString = "2010-06-28 15:26:02";
      var DateObject = ilios.utilities.mySQLDateToDateObject(mySQLDateString);
      var expected = new Date("2010-06-28 15:26:02");
      expect(DateObject).toEqual(expected);
    });

    it("should use UTC time if valueIsUTC is true", function () {
      var mySQLDateString = "2010-06-28 15:26:02";
      var DateObject = ilios.utilities.mySQLDateToDateObject(mySQLDateString, true);
      var expected = new Date("2010-06-28 15:26:02 UTC");
      expect(DateObject).toEqual(expected);
    });
  });

  describe("convertMimeTypeToCSSClassName()", function () {
    it("should return an empty string if mimeType is not a string", function () {
      var mimeType = 5;
      expect(ilios.utilities.convertMimeTypeToCSSClassName(mimeType)).toBe('');
    });

    it("should replace / with --", function () {
      var mimeType = "text/plain";
      expect(ilios.utilities.convertMimeTypeToCSSClassName(mimeType)).toBe('text--plain');
    });

    it("should replace . with __", function () {
      var mimeType = "image/vnd.adobe.photoshop";
      expect(ilios.utilities.convertMimeTypeToCSSClassName(mimeType)).toBe('image--vnd__adobe__photoshop');
    });
  });
});
<commit_msg>removeAllChildren() specs<commit_after>describe("ilios_utilities", function() {
  it("should create a utilities namespace on the ilios global object", function () {
    expect(typeof ilios.utilities).toBe("object");
  });

  it("should define 3 different user name formats", function () {
    var formats = [
      ilios.utilities.USER_NAME_FORMAT_LAST_FIRST,
      ilios.utilities.USER_NAME_FORMAT_FIRST_FIRST,
      ilios.utilities.USER_NAME_FORMAT_FIRST_INITIAL_FIRST
    ];
    expect(formats[0]).toBeDefined();
    expect(formats[1]).toBeDefined();
    expect(formats[2]).toBeDefined();
    expect(formats[0]).not.toEqual(formats[1]);
    expect(formats[0]).not.toEqual(formats[2]);
    expect(formats[1]).not.toEqual(formats[2]);
  });

  describe("setToolTipForElement()", function () {
    it("should set the title attribute of the element", function () {
      var element = document.createElement('div');
      var tooltip = "Should tooltip text really go in the title attribute?";
      ilios.utilities.setToolTipForElement(element, tooltip);
      expect(element.getAttribute('title')).toBe(tooltip);
    });
  });

  describe("getEventTarget()", function () {
    var event;
    var div;

    beforeEach(function () {
      // Don't use real events. Let those get found in integration tests.
      // Just use a simple object for testing instead. We're just testing
      // the logic in the method, not browser quirks, etc.
      event = {};
      div = document.createElement('div');
    });

    it("should return target attribute if it exists", function () {
      event.target = div;
      expect(ilios.utilities.getEventTarget(event)).toEqual(div);
    });

    it("should return srcElement attribute if target attribute does not exist", function () {
      event.srcElement = div;
      expect(ilios.utilities.getEventTarget(event)).toEqual(div);
    });
  });

  describe("getParsedResponseObjectFromFormUploadResponseText()", function () {
    it("should strip off leading and trailing
 tags", function () {
      var responseText = "
{\"foo\": \"bar\"}
";
      var parsed = ilios.utilities.getParsedResponseObjectFromFormUploadResponseText(responseText);
      expect(parsed).toEqual({foo: "bar"});
    });

    it("should strip off leading and trailing
 tags", function () {
      var responseText = "
{\"foo\": \"bar\"}
";
      var parsed = ilios.utilities.getParsedResponseObjectFromFormUploadResponseText(responseText);
      expect(parsed).toEqual({foo: "bar"});
    });

    it("should handle the string if there are no pre elements", function () {
      var responseText = "{\"foo\": \"bar\"}";
      var parsed = ilios.utilities.getParsedResponseObjectFromFormUploadResponseText(responseText);
      expect(parsed).toEqual({foo: "bar"});
    });

    it("should call ilios.global.defaultAJAXFailureHandler and return null if JSON is invalid", function () {
      var responseText = "invalid JSON!";
      spyOn(ilios.global, "defaultAJAXFailureHandler");
      var parsed = ilios.utilities.getParsedResponseObjectFromFormUploadResponseText(responseText);
      expect(ilios.global.defaultAJAXFailureHandler).toHaveBeenCalled();
      expect(parsed).toBe(null);
    });

    it("should not call ilios.global.defaultAJAXFailureHandler if JSON is valid", function () {
      var responseText = "{\"foo\": \"bar\"}";
      spyOn(ilios.global, "defaultAJAXFailureHandler");
      ilios.utilities.getParsedResponseObjectFromFormUploadResponseText(responseText);
      expect(ilios.global.defaultAJAXFailureHandler).not.toHaveBeenCalled();
    });
  });

  describe("dateObjectToMySQLFriendly()", function () {
    var utcDate = new Date("2010-06-28 15:26:02 UTC");
    var pdtDate = new Date("2010-06-28 15:26:02 PDT");

    it("should return MySQL-formatted date string for date object", function () {
      var mysqlFriendly = ilios.utilities.dateObjectToMySQLFriendly(utcDate);
      expect(mysqlFriendly).toBe("2010-06-28");
    });

    it("should return date but not time if includeTime is false", function () {
      var mysqlFriendly = ilios.utilities.dateObjectToMySQLFriendly(utcDate, false);
      expect(mysqlFriendly).toBe("2010-06-28");
    });

    it("should return the date and time if includeTime is true", function () {
      var mysqlFriendly = ilios.utilities.dateObjectToMySQLFriendly(utcDate, true);
      expect(mysqlFriendly).toBe("2010-06-28 15:26:02");
    });

    it("should convert time to UTC", function () {
      var mysqlFriendly = ilios.utilities.dateObjectToMySQLFriendly(pdtDate, true);
      expect(mysqlFriendly).toBe("2010-06-28 22:26:02");
    });
  });

  describe("mySQLTimelessDateToDateObject()", function () {
    it("should return a Date object for midnight local time of the yyyyMMDDStr", function () {
      var mySqlTime = ilios.utilities.mySQLTimelessDateToDateObject("2010-06-28");
      expect(mySqlTime).toEqual(new Date("2010-06-28 00:00:00"));
    });
  });

  describe("mySQLDateToDateObject()", function () {
    it("should work with a two-digit year", function () {
      // Current implementation requires a trailing space. Bug?
      // Current implementation accepts a two-digit year, but treats it like a two-digit year. 10 = 10 AD. Bug?
      // I'm guessing two-digit years and date-only (no time) just simply really aren't supported.
      var mySQLDateString = "10-06-28 ";
      var DateObject = ilios.utilities.mySQLDateToDateObject(mySQLDateString);
      var expected = new Date("June 28");
      expected.setFullYear(10);
      expect(DateObject).toEqual(expected);
    });

    it("should work without a timestamp", function () {
      // Current implementation requires a trailing space. Bug?
      var mySQLDateString = "2010-06-28 ";
      var DateObject = ilios.utilities.mySQLDateToDateObject(mySQLDateString);
      var expected = new Date("June 28, 2010");
      expect(DateObject).toEqual(expected);
    });

    it("should work with a timestamp", function () {
      var mySQLDateString = "2010-06-28 15:26:02";
      var DateObject = ilios.utilities.mySQLDateToDateObject(mySQLDateString);
      var expected = new Date("2010-06-28 15:26:02");
      expect(DateObject).toEqual(expected);
    });

    it("should use UTC time if valueIsUTC is true", function () {
      var mySQLDateString = "2010-06-28 15:26:02";
      var DateObject = ilios.utilities.mySQLDateToDateObject(mySQLDateString, true);
      var expected = new Date("2010-06-28 15:26:02 UTC");
      expect(DateObject).toEqual(expected);
    });
  });

  describe("convertMimeTypeToCSSClassName()", function () {
    it("should return an empty string if mimeType is not a string", function () {
      var mimeType = 5;
      expect(ilios.utilities.convertMimeTypeToCSSClassName(mimeType)).toBe('');
    });

    it("should replace / with --", function () {
      var mimeType = "text/plain";
      expect(ilios.utilities.convertMimeTypeToCSSClassName(mimeType)).toBe('text--plain');
    });

    it("should replace . with __", function () {
      var mimeType = "image/vnd.adobe.photoshop";
      expect(ilios.utilities.convertMimeTypeToCSSClassName(mimeType)).toBe('image--vnd__adobe__photoshop');
    });
  });

  describe("removeAllChildren()", function () {
    it("should return a childless element if passed a childless element", function () {
      var container = document.createElement('div');
      expect(container.hasChildNodes()).toBe(false);
      ilios.utilities.removeAllChildren(container);
      expect(container.hasChildNodes()).toBe(false);
    });

    it("should remove children from an element with children", function () {
      var container = document.createElement('div');
      container.appendChild(document.createElement('span'));
      expect(container.hasChildNodes()).toBe(true);
      ilios.utilities.removeAllChildren(container);
      expect(container.hasChildNodes()).toBe(false);
    });
  });
});
<|endoftext|>


<commit_before>import { moduleFor, test } from 'ember-qunit'
import { blocklyWorkspaceMock } from '../../helpers/mocks';

moduleFor('service:blocks-gallery', 'Unit | Service | blocks-gallery', {
    needs: ['service:blocksGallery', 'service:blockly'],
    setup() {
        blocklyWorkspaceMock()
        this.container.lookup('service:blocksGallery').start();
    }
})

///////////// PARAMS /////////////

let procedure = `
<block type="procedures_defnoreturn" id="whpKBVIV.;:t%=8XN+E_" x="778" y="185">
<mutation>
  <arg name="param"></arg>
</mutation>
<field name="NAME">Hacer algo</field>
<field name="ARG0">param</field>
<statement name="STACK">
  <block type="GirarGrados" id=";qf!gXUI;'/BUa0nx#y]">
    <value name="grados">
      <block type="variables_get" id="wAE7-:@m*P0G[x'Uf$Hv">
        <mutation var="param" parent="whpKBVIV.;:t%=8XN+E_"></mutation>
      </block>
    </value>
  </block>
</statement>
</block>
`

test('Parameter in parent procedure should be ok', function(assert) {
    let param = findParam(Blockly.textToBlock(procedure))
    assert.notOk(param.disabled)
    assert.notOk(param.warning)
});

let emptyProcedure = `
<block type="procedures_defnoreturn" id="whpKBVIV.;:t%=8XN+E_" x="41" y="112">
<mutation>
  <arg name="param"></arg>
</mutation>
<field name="NAME">Hacer algo</field>
<field name="ARG0">param</field>
</block>
`

let main = `
<block type="al_empezar_a_ejecutar" id="~7u[uK:$SQa$}1uY9,h6" deletable="false" movable="false" editable="false" x="15" y="15">
<statement name="program">
  <block type="GirarGrados" id="jvQK2Fm?8Sh72]]8qk$Z">
    <value name="grados">
      <block type="variables_get" id="wAE7-:@m*P0G[x'Uf$Hv">
        <mutation var="param" parent="whpKBVIV.;:t%=8XN+E_"></mutation>
      </block>
    </value>
  </block>
</statement>
</block>
`

test('Parameter in non parent procedure should be disabled and with warning', function(assert) {
    Blockly.textToBlock(emptyProcedure)
    let param = findParam(Blockly.textToBlock(main))
    assert.ok(param.disabled)
    // TODO: No sé dónde / cuando se guarda el Warning, por consola anda pero acá no (ni siquiera después de hacer setWarningText)
    // assert.equal(param.warning.getText(), "")
});

let flying = `
<block type="variables_get" id="wAE7-:@m*P0G[x'Uf$Hv" disabled="true" x="399" y="294">
<mutation var="param" parent="whpKBVIV.;:t%=8XN+E_"></mutation>
</block>
`

test('Parameter in non parent procedure should only be disabled', function(assert) {
    Blockly.textToBlock(emptyProcedure)
    let param = findParam(Blockly.textToBlock(flying))
    assert.ok(param.disabled)
    assert.notOk(param.warning)
});

let mainWithoutParent = `
<block type="al_empezar_a_ejecutar" id="~7u[uK:$SQa$}1uY9,h6" deletable="false" movable="false" editable="false" x="15" y="15">
<statement name="program">
  <block type="GirarGrados" id="jvQK2Fm?8Sh72]]8qk$Z">
    <value name="grados">
      <block type="variables_get" id="wAE7-:@m*P0G[x'Uf$Hv">
        <mutation var="param"></mutation>
      </block>
    </value>
  </block>
</statement>
</block>
`

test('Parameter without parent procedure should be always ok', function(assert) {
    let param = findParam(Blockly.textToBlock(mainWithoutParent))
    assert.notOk(param.disabled)
    assert.notOk(param.warning)
});

test('Parameter should dispose when procedure is disposed', function(assert) {
    let procedure = Blockly.textToBlock(emptyProcedure)
    let param = findParam(Blockly.textToBlock(flying))
    assert.ok(param.workspace)
    procedure.dispose()
    assertAsync(assert, function() {
        assert.notOk(param.workspace)
    })
});

function findParam(rootBlock) {
    let type = "variables_get"
    let param = rootBlock.type == type ? rootBlock : findChildren(rootBlock, type)
    param.onchange() // Force initialize
    return param
}

function findChildren(rootBlock, type) {
    return rootBlock.getChildren().find((b) => b.type == type) || findChildren(rootBlock.getChildren()[0], type)
}

function assertAsync(assert, fn) {
  let done = assert.async(1)
  setTimeout(function() {
      fn(); done()
  })
}

///////////// ALIAS /////////////

let testAlias = function (alias, type) {
    test(`check if ${alias} block definition exist and is equal to ${type} block definition`, function (assert) {
        assert.ok(this.subject().areAliases(alias, type));
    });
}

testAlias('si', 'Si');
testAlias('sino', 'SiNo');
testAlias('Sino', 'SiNo');
testAlias('hasta', 'Hasta');
testAlias('prenderCompuConColision', 'PrenderComputadora');
testAlias('PrenderCompu', 'PrenderComputadora');
testAlias('ApagarCompu', 'ApagarComputadora');
testAlias('SiguienteCompu', 'PasarASiguienteComputadora');
testAlias('Descubralculpable', 'EsCulpable');
testAlias('repetir', 'Repetir');
testAlias('tocandoBanana', 'TocandoBanana');
testAlias('tocandoManzana', 'TocandoManzana');
testAlias('PrenderFogata', 'PrenderFogata');
testAlias('Dejarregalo', 'DejarRegalo');
testAlias('Contarbanana', 'ContarBanana');
testAlias('Contarmanzana', 'ContarManzana');
testAlias('AvanzarKm', 'Avanzar1km');
testAlias('cambiarColor', 'CambiarColor');
testAlias('siguienteFoco', 'siguienteFoco');
testAlias('empezarFiesta', 'EmpezarFiesta');
testAlias('Volveralbordeizquierdo', 'VolverAlBordeIzquierdo');
testAlias('Primersospechoso', 'IrAlPrimerSospechoso');
testAlias('PrimerSospechoso', 'IrAlPrimerSospechoso');
testAlias('Siguientesospechoso', 'IrAlSiguienteSospechoso');
testAlias('SiguienteSospechoso', 'IrAlSiguienteSospechoso');
testAlias('Sacardisfraz', 'InterrogarSospechoso');
testAlias('SacarDisfraz', 'InterrogarSospechoso');
testAlias('Estoyenunaesquina', 'EstoyEnEsquina');
testAlias('tocandoFogata', 'TocandoFogata');
testAlias('tocandoInicio', 'TocandoInicio');
testAlias('tocandoFinal', 'TocandoFinal');
testAlias('tocandoPelota', 'TocandoPelota');
testAlias('tocandoQueso', 'TocandoQueso');
testAlias('tocandoLuz', 'TocandoLuz');
testAlias('Abrirojos', 'AbrirOjos');
testAlias('Cerrarojos', 'CerrarOjos');
testAlias('Soar', 'Soniar');
testAlias('Agarrarllave', 'AgarrarLlave');
testAlias('Abrircofre', 'AbrirCofre');
testAlias('Darsombrero', 'DarSombrero');
testAlias('Atacarconespada', 'AtacarConEspada');
testAlias('Escaparenunicornio', 'EscaparEnUnicornio');
testAlias('estoyInicio', 'EstoySobreElInicio');
testAlias('estoyAlInicio', 'EstoySobreElInicio');
testAlias('estoyFinColumna', 'EstoySobreElFinal');
testAlias('EstoyAlFin', 'EstoySobreElFinal');
testAlias('ComerBananaNano', 'ComerBanana');
testAlias('saltar1', 'SaltarHablando');<commit_msg>Testing warnings in param blocks<commit_after>import { moduleFor, test } from 'ember-qunit'
import { blocklyWorkspaceMock } from '../../helpers/mocks';

moduleFor('service:blocks-gallery', 'Unit | Service | blocks-gallery', {
    needs: ['service:blocksGallery', 'service:blockly'],
    setup() {
        blocklyWorkspaceMock()
        this.container.lookup('service:blocksGallery').start();
    }
})

///////////// PARAMS /////////////

let procedure = `
<block type="procedures_defnoreturn" id="whpKBVIV.;:t%=8XN+E_" x="778" y="185">
<mutation>
  <arg name="param"></arg>
</mutation>
<field name="NAME">Hacer algo</field>
<field name="ARG0">param</field>
<statement name="STACK">
  <block type="GirarGrados" id=";qf!gXUI;'/BUa0nx#y]">
    <value name="grados">
      <block type="variables_get" id="wAE7-:@m*P0G[x'Uf$Hv">
        <mutation var="param" parent="whpKBVIV.;:t%=8XN+E_"></mutation>
      </block>
    </value>
  </block>
</statement>
</block>
`

test('Parameter in parent procedure should be ok', function(assert) {
    let param = findParam(Blockly.textToBlock(procedure))
    assert.notOk(param.disabled)
    assert.notOk(param.warning)
});

let emptyProcedure = `
<block type="procedures_defnoreturn" id="whpKBVIV.;:t%=8XN+E_" x="41" y="112">
<mutation>
  <arg name="param"></arg>
</mutation>
<field name="NAME">Hacer algo</field>
<field name="ARG0">param</field>
</block>
`

let main = `
<block type="al_empezar_a_ejecutar" id="~7u[uK:$SQa$}1uY9,h6" deletable="false" movable="false" editable="false" x="15" y="15">
<statement name="program">
  <block type="GirarGrados" id="jvQK2Fm?8Sh72]]8qk$Z">
    <value name="grados">
      <block type="variables_get" id="wAE7-:@m*P0G[x'Uf$Hv">
        <mutation var="param" parent="whpKBVIV.;:t%=8XN+E_"></mutation>
      </block>
    </value>
  </block>
</statement>
</block>
`

test('Parameter in non parent procedure should be disabled and with warning', function(assert) {
    Blockly.textToBlock(emptyProcedure)
    let param = findParam(Blockly.textToBlock(main))
    assert.ok(param.disabled)
    assert.equal(param.warning.getText(), "Este bloque no puede usarse aquí. Es un parámetro que sólo puede usarse en Hacer algo.")
});

let flying = `
<block type="variables_get" id="wAE7-:@m*P0G[x'Uf$Hv" disabled="true" x="399" y="294">
<mutation var="param" parent="whpKBVIV.;:t%=8XN+E_"></mutation>
</block>
`

test('Parameter in non parent procedure should only be disabled', function(assert) {
    Blockly.textToBlock(emptyProcedure)
    let param = findParam(Blockly.textToBlock(flying))
    assert.ok(param.disabled)
    assert.notOk(param.warning)
});

let mainWithoutParent = `
<block type="al_empezar_a_ejecutar" id="~7u[uK:$SQa$}1uY9,h6" deletable="false" movable="false" editable="false" x="15" y="15">
<statement name="program">
  <block type="GirarGrados" id="jvQK2Fm?8Sh72]]8qk$Z">
    <value name="grados">
      <block type="variables_get" id="wAE7-:@m*P0G[x'Uf$Hv">
        <mutation var="param"></mutation>
      </block>
    </value>
  </block>
</statement>
</block>
`

test('Parameter without parent procedure should be always ok', function(assert) {
    let param = findParam(Blockly.textToBlock(mainWithoutParent))
    assert.notOk(param.disabled)
    assert.notOk(param.warning)
});

test('Parameter should dispose when procedure is disposed', function(assert) {
    let procedure = Blockly.textToBlock(emptyProcedure)
    let param = findParam(Blockly.textToBlock(flying))
    assert.ok(param.workspace)
    procedure.dispose()
    assertAsync(assert, function() {
        assert.notOk(param.workspace)
    })
});

function findParam(rootBlock) {
    let type = "variables_get"
    let param = rootBlock.type == type ? rootBlock : findChildren(rootBlock, type)
    param.onchange() // Force initialize
    return param
}

function findChildren(rootBlock, type) {
    return rootBlock.getChildren().find((b) => b.type == type) || findChildren(rootBlock.getChildren()[0], type)
}

function assertAsync(assert, fn) {
  let done = assert.async(1)
  setTimeout(function() {
      fn(); done()
  })
}

///////////// ALIAS /////////////

let testAlias = function (alias, type) {
    test(`check if ${alias} block definition exist and is equal to ${type} block definition`, function (assert) {
        assert.ok(this.subject().areAliases(alias, type));
    });
}

testAlias('si', 'Si');
testAlias('sino', 'SiNo');
testAlias('Sino', 'SiNo');
testAlias('hasta', 'Hasta');
testAlias('prenderCompuConColision', 'PrenderComputadora');
testAlias('PrenderCompu', 'PrenderComputadora');
testAlias('ApagarCompu', 'ApagarComputadora');
testAlias('SiguienteCompu', 'PasarASiguienteComputadora');
testAlias('Descubralculpable', 'EsCulpable');
testAlias('repetir', 'Repetir');
testAlias('tocandoBanana', 'TocandoBanana');
testAlias('tocandoManzana', 'TocandoManzana');
testAlias('PrenderFogata', 'PrenderFogata');
testAlias('Dejarregalo', 'DejarRegalo');
testAlias('Contarbanana', 'ContarBanana');
testAlias('Contarmanzana', 'ContarManzana');
testAlias('AvanzarKm', 'Avanzar1km');
testAlias('cambiarColor', 'CambiarColor');
testAlias('siguienteFoco', 'siguienteFoco');
testAlias('empezarFiesta', 'EmpezarFiesta');
testAlias('Volveralbordeizquierdo', 'VolverAlBordeIzquierdo');
testAlias('Primersospechoso', 'IrAlPrimerSospechoso');
testAlias('PrimerSospechoso', 'IrAlPrimerSospechoso');
testAlias('Siguientesospechoso', 'IrAlSiguienteSospechoso');
testAlias('SiguienteSospechoso', 'IrAlSiguienteSospechoso');
testAlias('Sacardisfraz', 'InterrogarSospechoso');
testAlias('SacarDisfraz', 'InterrogarSospechoso');
testAlias('Estoyenunaesquina', 'EstoyEnEsquina');
testAlias('tocandoFogata', 'TocandoFogata');
testAlias('tocandoInicio', 'TocandoInicio');
testAlias('tocandoFinal', 'TocandoFinal');
testAlias('tocandoPelota', 'TocandoPelota');
testAlias('tocandoQueso', 'TocandoQueso');
testAlias('tocandoLuz', 'TocandoLuz');
testAlias('Abrirojos', 'AbrirOjos');
testAlias('Cerrarojos', 'CerrarOjos');
testAlias('Soar', 'Soniar');
testAlias('Agarrarllave', 'AgarrarLlave');
testAlias('Abrircofre', 'AbrirCofre');
testAlias('Darsombrero', 'DarSombrero');
testAlias('Atacarconespada', 'AtacarConEspada');
testAlias('Escaparenunicornio', 'EscaparEnUnicornio');
testAlias('estoyInicio', 'EstoySobreElInicio');
testAlias('estoyAlInicio', 'EstoySobreElInicio');
testAlias('estoyFinColumna', 'EstoySobreElFinal');
testAlias('EstoyAlFin', 'EstoySobreElFinal');
testAlias('ComerBananaNano', 'ComerBanana');
testAlias('saltar1', 'SaltarHablando');<|endoftext|>


<commit_before>// Gives the parameter needed for ecrecover

function signature(data, nonce, rulesAddress) {
	var hash = web3.sha3(data, nonce, rulesAddress);
	var sig = web3.eth.sign(eth.accounts[0], hash);
	var r = "0x" + sig.slice(2, 66);
	var s = "0x" + sig.slice(66, 130);
	var v = 27 + Number(sig.slice(130, 132));
	var ecrecoverData = [hash, v, r, s];
	return ecrecoverData;
}
<commit_msg>forgot a web3 before my eth<commit_after>// Gives the parameter needed for ecrecover

function signature(data, nonce, rulesAddress) {
	var hash = web3.sha3(data, nonce, rulesAddress);
	var sig = web3.eth.sign(web3.eth.accounts[0], hash);
	var r = "0x" + sig.slice(2, 66);
	var s = "0x" + sig.slice(66, 130);
	var v = 27 + Number(sig.slice(130, 132));
	var ecrecoverData = [hash, v, r, s];
	return ecrecoverData;
}
<|endoftext|>


<commit_before>var ClickHouse = require ("../src/clickhouse");

var http = require ('http');
var url  = require ('url');
var qs   = require ('querystring');

var assert = require ("assert");

describe ("error parsing", function () {

	var server,
		host = process.env.CLICKHOUSE_HOST || '127.0.0.1',
		port = process.env.CLICKHOUSE_PORT || 8123,
		dbCreated = false;

	it ("returns error for unknown sql", function (done) {
		var ch = new ClickHouse ({host: host, port: port, useQueryString: true});
		var stream = ch.query ("ABCDEFGHIJKLMN", {syncParser: true}, function (err, result) {
			// assert (err);
			// done ();
		});

		stream.on ('error', function (err) {

			assert (err);
			assert (err.message.match (/Syntax error/));
			assert.equal (err.lineno, 1, "line number should eq 1");
			assert.equal (err.colno, 1, "col  number should eq 1");
			// console.log (err);
			done();
		});
	});

	it ("returns error with line/col for sql with garbage", function (done) {
		var ch = new ClickHouse ({host: host, port: port, useQueryString: true});
		var stream = ch.query ("CREATE\n\t\tABCDEFGHIJKLMN", {syncParser: true}, function (err, result) {
			// assert (err);
			// done ();
		});

		stream.on ('error', function (err) {

			assert (err);
			assert (err.message.match (/Syntax error/));
			assert.equal (err.lineno, 2, "line number should eq 2");
			assert.equal (err.colno, 3, "col  number should eq 3");
			// console.log (err);
			done();
		});
	});

	it ("returns error for empty sql", function (done) {
		var ch = new ClickHouse ({host: host, port: port, useQueryString: true});

		function countCallbacks (err) {
			countCallbacks.count = (countCallbacks.count || 0) + 1;

			if (countCallbacks.count === 2) {
				//
				done ();
			}
		}

		var stream = ch.query ("-- nothing here", {syncParser: true}, function (err, result) {
			countCallbacks (err);
			// assert (err);
			// done ();
		});

		stream.on ('error', function (err) {

			// console.log (err); // failed at end of query

			assert (err);
			assert (err.message.match (/Syntax error/));
			assert.ifError ('lineno' in err);
			assert.ifError ('colno'  in err);

			countCallbacks (err);
		});
	});

	it ("returns error for unknown table", function (done) {
		var ch = new ClickHouse ({host: host, port: port, useQueryString: true});
		var stream = ch.query ("SELECT * FROM xxx", {syncParser: true}, function (err, result) {
			// assert (err);
			// done ();
		});

		stream.on ('error', function (err) {

			assert (err);
			assert.ifError (err.message.match (/Syntax error/));
			assert.ifError ('lineno' in err);
			assert.ifError ('colno'  in err);

			done();
		});
	});

});
<commit_msg>errror case for #3<commit_after>var ClickHouse = require ("../src/clickhouse");

var http = require ('http');
var url  = require ('url');
var qs   = require ('querystring');

var assert = require ("assert");

describe ("error parsing", function () {

	var server,
		host = process.env.CLICKHOUSE_HOST || '127.0.0.1',
		port = process.env.CLICKHOUSE_PORT || 8123,
		dbCreated = false;

	it ("will not throw on http error", function (done) {
		var ch = new ClickHouse ({host: host, port: 59999, useQueryString: true});
		var stream = ch.query ("ABCDEFGHIJKLMN", {syncParser: true}, function (err, result) {
			// assert (err);
			// done ();
		});

		stream.on ('error', function (err) {
			done();
		});
	});

	it ("returns error for unknown sql", function (done) {
		var ch = new ClickHouse ({host: host, port: port, useQueryString: true});
		var stream = ch.query ("ABCDEFGHIJKLMN", {syncParser: true}, function (err, result) {
			// assert (err);
			// done ();
		});

		stream.on ('error', function (err) {

			assert (err);
			assert (err.message.match (/Syntax error/));
			assert.equal (err.lineno, 1, "line number should eq 1");
			assert.equal (err.colno, 1, "col  number should eq 1");
			// console.log (err);
			done();
		});
	});

	it ("returns error with line/col for sql with garbage", function (done) {
		var ch = new ClickHouse ({host: host, port: port, useQueryString: true});
		var stream = ch.query ("CREATE\n\t\tABCDEFGHIJKLMN", {syncParser: true}, function (err, result) {
			// assert (err);
			// done ();
		});

		stream.on ('error', function (err) {

			assert (err);
			assert (err.message.match (/Syntax error/));
			assert.equal (err.lineno, 2, "line number should eq 2");
			assert.equal (err.colno, 3, "col  number should eq 3");
			// console.log (err);
			done();
		});
	});

	it ("returns error for empty sql", function (done) {
		var ch = new ClickHouse ({host: host, port: port, useQueryString: true});

		function countCallbacks (err) {
			countCallbacks.count = (countCallbacks.count || 0) + 1;

			if (countCallbacks.count === 2) {
				//
				done ();
			}
		}

		var stream = ch.query ("-- nothing here", {syncParser: true}, function (err, result) {
			countCallbacks (err);
			// assert (err);
			// done ();
		});

		stream.on ('error', function (err) {

			// console.log (err); // failed at end of query

			assert (err);
			assert (err.message.match (/Syntax error/));
			assert.ifError ('lineno' in err);
			assert.ifError ('colno'  in err);

			countCallbacks (err);
		});
	});

	it ("returns error for unknown table", function (done) {
		var ch = new ClickHouse ({host: host, port: port, useQueryString: true});
		var stream = ch.query ("SELECT * FROM xxx", {syncParser: true}, function (err, result) {
			// assert (err);
			// done ();
		});

		stream.on ('error', function (err) {

			assert (err);
			assert.ifError (err.message.match (/Syntax error/));
			assert.ifError ('lineno' in err);
			assert.ifError ('colno'  in err);

			done();
		});
	});

});
<|endoftext|>


<commit_before>const fs = require("fs-extra-promise");
const { sep } = require("path");

const sendHelpMessage = (client, msg, cmd) => client.commands.get("help").run(client, msg, [cmd]);

/* Returns an array of dir (including trailing slash) and filename */
const getPiecePath = async (client, type, name, obj) => {
  // Komada base dirs already end with sep
  const category = (obj.help ? obj.help.category : null) || "General";
  const subCategory = (obj.help ? obj.help.subCategory : null) || "General";
  const catDir = (category === "General" ? "" : sep + category) +
    (subCategory === "General" ? "" : sep + subCategory);
  const clientDir = `${client.clientBaseDir}${type}s${catDir}`;

  // See if it's a client piece (or overrides a core piece)
  return fs.accessAsync(`${clientDir}${sep}${name}.js`)
  .then(() => [`${clientDir}${sep}`, `${name}.js`])
  .catch(() => {
    // It must be a core piece
    const coreDir = `${client.coreBaseDir}${type}s${catDir}`;
    return fs.accessAsync(`${coreDir}${sep}${name}.js`)
      .then(() => [`${coreDir}${sep}`, `${name}.js`])
      // Or...maybe not. Can't find it ¯\_(ツ)_/¯
      .catch(() => [null, null]);
  });
};

const sendDebugMessage = async (client, msg, type, name, obj) => {
  const [dir, filename] = await getPiecePath(client, type, name, obj);
  return msg.channel.send(`location :: ${dir}\n${filename}\nType \`${msg.guildConf.prefix}debug ${type} ${name} src\` to see source`, { code: "asciidoc" });
};

const sendSrcMessage = async (client, chan, type, name, obj) => {
  const [dir, filename] = await getPiecePath(client, type, name, obj);
  if (dir && filename) {
    const src = await fs.readFileAsync(dir + filename);
    if (src) return chan.send("js", src, { code: "js", split: true });
    return chan.send("Something went wrong; could not load source", { code: true });
  }
  return chan.send("Could not find piece", { code: true });
};

const runShowPiece = async (client, msg, type, name, obj) => {
  if (type === "command") await sendHelpMessage(client, msg, name);
  return sendDebugMessage(client, msg, type, name, obj);
};

const runShowPieceSrc = (client, msg, type, name, obj) => sendSrcMessage(client, msg.channel, type, name, obj);

const runListPieces = (client, chan, type, pieces) => {
  const piecesNames = pieces instanceof Map ?
    pieces.keyArray() :
    Object.keys(pieces);
  const piecesMsg = piecesNames.length > 0 ?
    piecesNames.reduce((acc, name) => `${acc}, ${name}`) :
    `No ${type}s loaded`;
  return chan.send(piecesMsg, { code: true }).catch(console.error);
};

exports.run = async (client, msg, [type, name, src]) => {
  const pieces = client[{
    command: "commands",
    inhibitor: "commandInhibitors",
    monitor: "messageMonitors",
    function: "funcs",
    provider: "providers",
  }[type]];
  if (name === "*") {
    return runListPieces(client, msg.channel, type, pieces);
  }
  const obj = pieces instanceof Map ?
    pieces.get(name) :
    pieces[name];
  if (!obj) {
    return msg.channel.send(`That ${type} doesn't exist`, { code: true })
      .catch(console.error);
  }
  if (src) {
    return runShowPieceSrc(client, msg, type, name, obj);
  }
  return runShowPiece(client, msg, type, name, obj);
};

exports.conf = {
  enabled: true,
  selfbot: false,
  runIn: ["text", "dm", "group"],
  aliases: [],
  permLevel: 10,
  botPerms: [],
  requiredFuncs: [],
};

exports.help = {
  name: "debug",
  description: "Show debugging info on some thing or list all things.",
  usage: "<command|inhibitor|monitor|function|provider> <name:str> [src]",
  usageDelim: " ",
  extendedHelp: "Use `*` as name to list all pieces of that type.",
  type: "commands",
};
<commit_msg>ESLint. Again.<commit_after>const fs = require("fs-extra-promise");
const { sep } = require("path");

const sendHelpMessage = (client, msg, cmd) => client.commands.get("help").run(client, msg, [cmd]);

/* Returns an array of dir (including trailing slash) and filename */
const getPiecePath = async (client, type, name, obj) => {
  // Komada base dirs already end with sep
  const category = (obj.help ? obj.help.category : null) || "General";
  const subCategory = (obj.help ? obj.help.subCategory : null) || "General";
  const catDir = (category === "General" ? "" : sep + category) +
    (subCategory === "General" ? "" : sep + subCategory);
  const clientDir = `${client.clientBaseDir}${type}s${catDir}`;

  // See if it's a client piece (or overrides a core piece)
  return fs.accessAsync(`${clientDir}${sep}${name}.js`)
    .then(() => [`${clientDir}${sep}`, `${name}.js`])
    .catch(() => {
      const coreDir = `${client.coreBaseDir}${type}s${catDir}`;
      return fs.accessAsync(`${coreDir}${sep}${name}.js`)
        .then(() => [`${coreDir}${sep}`, `${name}.js`])
        .catch(() => [null, null]);
    });
};

const sendDebugMessage = async (client, msg, type, name, obj) => {
  const [dir, filename] = await getPiecePath(client, type, name, obj);
  return msg.channel.send(`location :: ${dir}\n${filename}\nType \`${msg.guildConf.prefix}debug ${type} ${name} src\` to see source`, { code: "asciidoc" });
};

const sendSrcMessage = async (client, chan, type, name, obj) => {
  const [dir, filename] = await getPiecePath(client, type, name, obj);
  if (dir && filename) {
    const src = await fs.readFileAsync(dir + filename);
    if (src) return chan.send("js", src, { code: "js", split: true });
    return chan.send("Something went wrong; could not load source", { code: true });
  }
  return chan.send("Could not find piece", { code: true });
};

const runShowPiece = async (client, msg, type, name, obj) => {
  if (type === "command") await sendHelpMessage(client, msg, name);
  return sendDebugMessage(client, msg, type, name, obj);
};

const runShowPieceSrc = (client, msg, type, name, obj) => sendSrcMessage(client, msg.channel, type, name, obj);

const runListPieces = (client, chan, type, pieces) => {
  const piecesNames = pieces instanceof Map ?
    pieces.keyArray() :
    Object.keys(pieces);
  const piecesMsg = piecesNames.length > 0 ?
    piecesNames.reduce((acc, name) => `${acc}, ${name}`) :
    `No ${type}s loaded`;
  return chan.send(piecesMsg, { code: true }).catch(console.error);
};

exports.run = async (client, msg, [type, name, src]) => {
  const pieces = client[{
    command: "commands",
    inhibitor: "commandInhibitors",
    monitor: "messageMonitors",
    function: "funcs",
    provider: "providers",
  }[type]];
  if (name === "*") {
    return runListPieces(client, msg.channel, type, pieces);
  }
  const obj = pieces instanceof Map ?
    pieces.get(name) :
    pieces[name];
  if (!obj) {
    return msg.channel.send(`That ${type} doesn't exist`, { code: true })
      .catch(console.error);
  }
  if (src) {
    return runShowPieceSrc(client, msg, type, name, obj);
  }
  return runShowPiece(client, msg, type, name, obj);
};

exports.conf = {
  enabled: true,
  selfbot: false,
  runIn: ["text", "dm", "group"],
  aliases: [],
  permLevel: 10,
  botPerms: [],
  requiredFuncs: [],
};

exports.help = {
  name: "debug",
  description: "Show debugging info on some thing or list all things.",
  usage: "<command|inhibitor|monitor|function|provider> <name:str> [src]",
  usageDelim: " ",
  extendedHelp: "Use `*` as name to list all pieces of that type.",
  type: "commands",
};
<|endoftext|>


<commit_before>/*
 * This program is part of the OpenLMIS logistics management information system platform software.
 * Copyright © 2013 VillageReach
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License along with this program.  If not, see http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org.
 */

//  Description:
//  Freezing the top header of R&R products table upon scroll

app.directive('fixedTableHeader', function () {
  return {
    restrict: 'EA',
    link: function (scope, element) {
      var fixedHeader = $("

");
      var previousWidth = 0, previousHeight = 0;
      fixedHeader.hide();

      var cloneAndAppendTableHeader = function () {
        var table = $("

");
        table.append(element.find('thead').clone());
        fixedHeader.append(table);
        element.parent().append(fixedHeader);
      };

      setTimeout(function () {
        cloneAndAppendTableHeader();
        element.parent().scroll(function () {
          fixedHeader.scrollLeft(element.parent().scrollLeft());
        });
      });

      function setWidthAndHeightFromParent() {
        var parentWidth = element.parent().width();
        var parentHeight = element.find('thead').height();

        if (previousWidth != parentWidth) {
          fixedHeader.width(parentWidth);
          previousWidth = parentWidth;
        }

        if (previousHeight != parentHeight) {
          fixedHeader.find('thead tr').height(parentHeight);
          previousHeight = parentHeight;
        }
      }

      angular.element('.rnr-body').scroll(function () {
        fixedHeader.hide();
        if (element.offset().top < 0 && element.is(':visible')) {
          setWidthAndHeightFromParent();
          fixedHeader.show();
        }
      });

      $(window).on('resize', function () {
        setWidthAndHeightFromParent();
      });
    }
  };
});

var viewFixedHeaderOnScroll = function (fixedHeaderElement, element) {
  angular.element('.rnr-body').scroll(function () {
    fixedHeaderElement.hide();
    if (element.offset().top < 0 && !element.is(':hidden') && fixedHeaderElement.is(':hidden')) {
      fixedHeaderElement.show();
      fixedHeaderElement.scrollLeft(element.parent().scrollLeft());
    }
  });
};
<commit_msg>#1201 | Floating header is now in sync with the normal header. Removed unused method viewFixedHeaderOnScroll from fixed-table-header<commit_after>/*
 * This program is part of the OpenLMIS logistics management information system platform software.
 * Copyright © 2013 VillageReach
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License along with this program.  If not, see http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org.
 */

//  Description:
//  Freezing the top header of R&R products table upon scroll

app.directive('fixedTableHeader', function () {
  return {
    restrict: 'EA',
    link: function (scope, element) {
      var fixedHeader = $("

");
      var previousWidth = 0, previousHeight = 0;
      fixedHeader.hide();

      var cloneAndAppendTableHeader = function () {
        var table = $("

");
        table.append(element.find('thead').clone());
        fixedHeader.append(table);
        element.parent().append(fixedHeader);
      };

      setTimeout(function () {
        cloneAndAppendTableHeader();
        element.parent().scroll(function () {
          fixedHeader.scrollLeft(element.parent().scrollLeft());
        });
      });

      function setWidthAndHeightFromParent() {
        var parentWidth = element.parent().width();
        var parentHeight = element.find('thead').height();

        if (previousWidth != parentWidth) {
          fixedHeader.width(parentWidth);
          previousWidth = parentWidth;
        }

        if (previousHeight != parentHeight) {
          fixedHeader.find('thead tr').height(parentHeight);
          previousHeight = parentHeight;
        }
      }

      angular.element('.rnr-body').scroll(function () {
        fixedHeader.hide();
        if (element.offset().top < 0 && element.is(':visible')) {
          setWidthAndHeightFromParent();
          fixedHeader.show();
          fixedHeader.scrollLeft(element.parent().scrollLeft());
        }
      });

      $(window).on('resize', function () {
        setWidthAndHeightFromParent();
      });
    }
  };
});
<|endoftext|>


<commit_before>$(document).ready(function(){

	var
		TypeAheader = window.Diaphanum.TypeAheader,
		typeAheadConfig = {
			template : $("#person-autocomplete-template").html(),
			name : "names" + _.uniqueId()
		};

	var typeAheadCallbackCreator = function(closestFieldContainerClass, idContainerClass) {
		return function(data) {
			$(this)
				.closest(closestFieldContainerClass)
				.find("input" + idContainerClass)
				.val(data.id);
		};
	};

	var excusedCallback = typeAheadCallbackCreator(".excused-member-field", ".excused-id-container");
	var absentCallback = typeAheadCallbackCreator(".absent-member-field", ".absent-id-container");
	var attendentsCallback = typeAheadCallbackCreator(".attendents-member-field", ".attendents-id-container");

	$(".protocol-form")
		.on("click", ".add-excused", function(){
			var newExcusedFieldHtml = $("#new-excused").html();
			// use underscore if any placeholders
			$(newExcusedFieldHtml).insertBefore("#excused-error");

			TypeAheader.feed(
				$("input.autocomplete.excused").not(".tt-query"),
				typeAheadConfig,
				excusedCallback);
		})
		.on("click", ".remove-excused", function(){
			$(this).parent().remove();
		})
		.on("click", ".add-absent", function(){
			var newAbsentFieldHtml = $("#new-absent").html();
			// use underscore if any placeholders
			$(newAbsentFieldHtml).insertBefore("#absent-error");

			TypeAheader.feed(
				$("input.autocomplete.absent").not(".tt-query"),
				typeAheadConfig,
				absentCallback );
		})
		.on("click", ".remove-absent", function(){
			$(this).parent().remove();
		})
		.on("click", ".add-attendents", function(){
			var newAttendentsFieldHtml = $("#new-attendents").html();
			// use underscore if any placeholders
			$(newAttendentsFieldHtml).insertBefore("#attendents-error");

			TypeAheader.feed(
				$("input.autocomplete.attendents").not(".tt-query"),
				typeAheadConfig,
				attendentsCallback);
		})
		.on("click", ".remove-attendents", function(){
			$(this).parent().remove();
		})
		.on("click", ".add-field", function(){
			var newAddMoreFieldHtml = $("#new-field").html();
			// use underscore if any placeholders
			$(newAddMoreFieldHtml).insertBefore($(this));
			$(this).remove();
		});

		// initialize the fist inputs to be typeaheads
		TypeAheader.feed($("input.autocomplete.excused"), typeAheadConfig, excusedCallback);
		TypeAheader.feed($("input.autocomplete.absent"), typeAheadConfig, absentCallback);
		TypeAheader.feed($("input.autocomplete.attendents"), typeAheadConfig, attendentsCallback);

		TypeAheader.feed($("input.autocomplete#institution"), {
			name : "institutions",
			template : $("#institution-autocomplete-template").html(),
			valueKey : "name",
			remote : {
				url : window.Diaphanum.appConfig.institutionSearchUrl + "%QUERY/",
				filter : function(parsedResponse) {
					return parsedResponse;
				}
			}
		}, function(data, event) {
			console.log(data);
			$(this)
				.closest(".controls")
				.find("#institutionIdContainer")
				.val(data.id);
		});

		// will be merged with the top $(".protocol-form")

		var addNewTopicInVote = function() {
			var newTopicVoteHtml = $("#new-topic-vote-template").html();
			$(newTopicVoteHtml).appendTo($(".topic-vote-container > .controls > ol"));
		};

		var removeTopicFromVote = function(topicIndex) {
			var
				selectorTemplate = ".topic-vote-container > .controls > ol > li:nth-child(<%= topicIndex %>)",
				compiledSelector = _.template(selectorTemplate, {
				topicIndex : topicIndex + 1 // n-th child starts from index 1
			});

			$(compiledSelector).remove();
		};

		var updateTopicNameInVote = function(topicIndex, topicName) {
			console.log(topicIndex, topicName);
			var
				selectorTemplate = ".topic-vote-container > .controls > ol > li:nth-child(<%= topicIndex %>) .voteTopic",
				compiledSelector = _.template(selectorTemplate, {
				topicIndex : topicIndex + 1 // n-th child starts from index 1
			});
			$(compiledSelector).val(topicName);
		};

		$(".protocol-form")
			.on("click", "#add-new-topic-button", function() {
				console.log("I am being clicked");
				var newTopicHtml = $("#new-topic-template").html();

				$(newTopicHtml).appendTo($(".topics-container"));
				addNewTopicInVote();
			})
			.on("click", ".remove-topic-button", function() {
				var index = $(this).parent().index();
				$(this)
					.parent()
					.remove();
				// update the votes accordingly
				removeTopicFromVote(index);
			})
			.on("keyup", ".topic", function() {
				updateTopicNameInVote($(this).parent().index(), $(this).val());
			});
});<commit_msg>topics-TOTAL_FORMS js implementation<commit_after>$(document).ready(function(){

	var
		TypeAheader = window.Diaphanum.TypeAheader,
		typeAheadConfig = {
			template : $("#person-autocomplete-template").html(),
			name : "names" + _.uniqueId()
		};

	var typeAheadCallbackCreator = function(closestFieldContainerClass, idContainerClass) {
		return function(data) {
			$(this)
				.closest(closestFieldContainerClass)
				.find("input" + idContainerClass)
				.val(data.id);
		};
	};

	var excusedCallback = typeAheadCallbackCreator(".excused-member-field", ".excused-id-container");
	var absentCallback = typeAheadCallbackCreator(".absent-member-field", ".absent-id-container");
	var attendentsCallback = typeAheadCallbackCreator(".attendents-member-field", ".attendents-id-container");

	var topicsCount = 1; //TODO: Check if it is posible to have protocol with no topics

	$(".protocol-form")
		.on("click", ".add-excused", function(){
			var newExcusedFieldHtml = $("#new-excused").html();
			// use underscore if any placeholders
			$(newExcusedFieldHtml).insertBefore("#excused-error");

			TypeAheader.feed(
				$("input.autocomplete.excused").not(".tt-query"),
				typeAheadConfig,
				excusedCallback);
		})
		.on("click", ".remove-excused", function(){
			$(this).parent().remove();
		})
		.on("click", ".add-absent", function(){
			var newAbsentFieldHtml = $("#new-absent").html();
			// use underscore if any placeholders
			$(newAbsentFieldHtml).insertBefore("#absent-error");

			TypeAheader.feed(
				$("input.autocomplete.absent").not(".tt-query"),
				typeAheadConfig,
				absentCallback );
		})
		.on("click", ".remove-absent", function(){
			$(this).parent().remove();
		})
		.on("click", ".add-attendents", function(){
			var newAttendentsFieldHtml = $("#new-attendents").html();
			// use underscore if any placeholders
			$(newAttendentsFieldHtml).insertBefore("#attendents-error");

			TypeAheader.feed(
				$("input.autocomplete.attendents").not(".tt-query"),
				typeAheadConfig,
				attendentsCallback);
		})
		.on("click", ".remove-attendents", function(){
			$(this).parent().remove();
		})
		.on("click", ".add-field", function(){
			var newAddMoreFieldHtml = $("#new-field").html();
			// use underscore if any placeholders
			$(newAddMoreFieldHtml).insertBefore($(this));
			$(this).remove();
		});

		// initialize the fist inputs to be typeaheads
		TypeAheader.feed($("input.autocomplete.excused"), typeAheadConfig, excusedCallback);
		TypeAheader.feed($("input.autocomplete.absent"), typeAheadConfig, absentCallback);
		TypeAheader.feed($("input.autocomplete.attendents"), typeAheadConfig, attendentsCallback);

		TypeAheader.feed($("input.autocomplete#institution"), {
			name : "institutions",
			template : $("#institution-autocomplete-template").html(),
			valueKey : "name",
			remote : {
				url : window.Diaphanum.appConfig.institutionSearchUrl + "%QUERY/",
				filter : function(parsedResponse) {
					return parsedResponse;
				}
			}
		}, function(data, event) {
			console.log(data);
			$(this)
				.closest(".controls")
				.find("#institutionIdContainer")
				.val(data.id);
		});

		// will be merged with the top $(".protocol-form")

		var addNewTopicInVote = function() {
			var newTopicVoteHtml = $("#new-topic-vote-template").html();
			$(newTopicVoteHtml).appendTo($(".topic-vote-container > .controls > ol"));
			topicsCount++;
			updateTopicsTotalForm();
		};

		var removeTopicFromVote = function(topicIndex) {
			var
				selectorTemplate = ".topic-vote-container > .controls > ol > li:nth-child(<%= topicIndex %>)",
				compiledSelector = _.template(selectorTemplate, {
				topicIndex : topicIndex + 1 // n-th child starts from index 1
			});

			$(compiledSelector).remove();
			topicsCount--;
			updateTopicsTotalForm();
		};

		var updateTopicNameInVote = function(topicIndex, topicName) {
			console.log(topicIndex, topicName);
			var
				selectorTemplate = ".topic-vote-container > .controls > ol > li:nth-child(<%= topicIndex %>) .voteTopic",
				compiledSelector = _.template(selectorTemplate, {
				topicIndex : topicIndex + 1 // n-th child starts from index 1
			});
			$(compiledSelector).val(topicName);
		};

		var updateTopicsTotalForm = function(){
			$("input[name='topics-TOTAL_FORMS']").val(topicsCount);
		};

		$(".protocol-form")
			.on("click", "#add-new-topic-button", function() {
				console.log("I am being clicked");
				var newTopicHtml = $("#new-topic-template").html();

				$(newTopicHtml).appendTo($(".topics-container"));
				addNewTopicInVote();
			})
			.on("click", ".remove-topic-button", function() {
				var index = $(this).parent().index();
				$(this)
					.parent()
					.remove();
				// update the votes accordingly
				removeTopicFromVote(index);
			})
			.on("keyup", ".topic", function() {
				updateTopicNameInVote($(this).parent().index(), $(this).val());
			});
});<|endoftext|>


<commit_before>//
// GUI for crop node
//

var OCRJS = OCRJS || {};
OCRJS.NodeGui = OCRJS.NodeGui || {}

OCRJS.NodeGui.CropGui = OCRJS.NodeGui.BaseGui.extend({
    constructor: function(node, viewer) {
        this.base(node, viewer, "cropgui");

        this._color = "#FFBBBB";
        this._rect = document.createElement("div");
        $(this._rect).css({
            borderColor: this._color,
        });
        this._makeTransformable(this._rect);
        this._hndl = new Seadragon.MouseTracker(this._rect);

        var sdrect = null; // TODO: Get rect of document!
        this._viewer.activeViewer().drawer.addOverlay(this._rect, sdrect);
        this.registerListener("onCanvasChanged");
    },

    setupEvents: function() {
        this.base();

        this._canvas.bind("mousedown.drawcanvas", function(event) {
            var dragstart = {x: event.pageX, y: event.pageY };
            // initialise drawing
            var droprect = null;
            self._canvas.bind("mousemove.drawcanvas", function(event) {
                var create = false;
                if (self._normalisedRectArea(dragstart.x, dragstart.y,
                        event.pageX, event.pageY) > 300) {
                    self._initialiseNewDrag();
                    create = true;
                }

                if (create) {
                    var x0 = dragstart.x - self._canvas.offset().left,
                        y0 = dragstart.y - self._canvas.offset().top,
                        x1 = event.pageX - self._canvas.offset().left,
                        y1 = event.pageY - self._canvas.offset().top,
                        sdrect = self._normalisedRect(x0, y0, x1, y1);
                    self._viewer.activeViewer().drawer.updateOverlay(self._rect, sdrect);
                }
            });

            self._canvas.bind("mouseup.drawcanvas", function(event) {
                self.dragDone();
            });
        });

        this._hndl.pressHandler = function(tracker, pos, quick, shift) {
            self._viewer.activeViewer().setMouseNavEnabled(false);
        }
        this._hndl.clickHandler = function(tracker, pos, quick, shift) {
            //if (shift)
            //    self._deleteRect(tracker.target);
        }
        this._hndl.enterHandler = function(tracker, pos, btelem, btany) {
            //$(window).bind("keydown.setorder", function(event) {
            //    if (event.keyCode >= KC_ONE && event.keyCode <= KC_NINE)
            //        self._setRectOrder(
            //                tracker.target, event.keyCode - KC_ZERO);
            //});
        }
        this._hndl.exitHandler = function(tracker, pos, btelem, btany) {
            //$(window).unbind("keydown.setorder");
        }
        this._hndl.dragHandler = function(tracker, pos, delta, shift) {
        }

        this._hndl.releaseHandler = function(tracker, pos, insidepress, insiderelease) {
            self._viewer.activeViewer().setMouseNavEnabled(true);
            var ele = $(tracker.target),
                x0 = ele.position().left,
                y0 = ele.position().top,
                x1 = x0 + ele.width(),
                y1 = y0 + ele.height(),
                sdrect = self._normalisedRect(x0, y0, x1, y1);
            self._viewer.activeViewer().drawer.updateOverlay(tracker.target, sdrect);
        }
    },

    dragDone: function() {
        this._hndl.setTracking(true);
        this._canvas.unbind("mousemove.drawcanvas");
        this._canvas.unbind("mouseup.drawcanvas");
        this.callListeners("onCanvasChanged");
    },

    _initialiseNewDrag: function() {
        var self = this;

    },
});
<commit_msg>More working towards something that might work<commit_after>//
// GUI for crop node
//

var OCRJS = OCRJS || {};
OCRJS.NodeGui = OCRJS.NodeGui || {}

OCRJS.NodeGui.CropGui = OCRJS.NodeGui.BaseGui.extend({
    constructor: function(node, viewer) {
        this.base(node, viewer, "cropgui");

        this._coords = [];
        this._color = "#FFBBBB";
        this.registerListener("onCanvasChanged");
    },

    getData: function() {
        if (this._coords.length < 4)
            return { x0: -1, y0: -1,x1: -1,y1: -1 };
        return {
            x0: this._coords[0],
            y0: this._coords[1],
            x1: this._coords[2],
            y1: this._coords[3],
        };
    },

    handles: function() {
        return: ["x0", "y0", "x1", "y1"];
    },

    setup: function() {
        this._rect = document.createElement("div");
        $(this._rect).css({
            borderColor: this._color,
        });
        this._makeTransformable(this._rect);
        this._hndl = new Seadragon.MouseTracker(this._rect);

        var sdrect = null; // TODO: Get rect of document!
        this._viewer.activeViewer().drawer.addOverlay(this._rect, sdrect);
    },

    tearDown: function() {
        $(this._rect).remove();
    },

    setupEvents: function() {
        this.base();

        this._canvas.bind("mousedown.drawcanvas", function(event) {
            var dragstart = {x: event.pageX, y: event.pageY };
            // initialise drawing
            var droprect = null;
            self._canvas.bind("mousemove.drawcanvas", function(event) {
                var create = false;
                if (self._normalisedRectArea(dragstart.x, dragstart.y,
                        event.pageX, event.pageY) > 300) {
                    self._initialiseNewDrag();
                    create = true;
                }

                if (create) {
                    var x0 = dragstart.x - self._canvas.offset().left,
                        y0 = dragstart.y - self._canvas.offset().top,
                        x1 = event.pageX - self._canvas.offset().left,
                        y1 = event.pageY - self._canvas.offset().top,
                        sdrect = self._normalisedRect(x0, y0, x1, y1);
                    self._viewer.activeViewer().drawer.updateOverlay(self._rect, sdrect);
                }
            });

            self._canvas.bind("mouseup.drawcanvas", function(event) {
                self.dragDone();
            });
        });

        this._hndl.pressHandler = function(tracker, pos, quick, shift) {
            self._viewer.activeViewer().setMouseNavEnabled(false);
        }
        this._hndl.clickHandler = function(tracker, pos, quick, shift) {
            //if (shift)
            //    self._deleteRect(tracker.target);
        }
        this._hndl.enterHandler = function(tracker, pos, btelem, btany) {
            //$(window).bind("keydown.setorder", function(event) {
            //    if (event.keyCode >= KC_ONE && event.keyCode <= KC_NINE)
            //        self._setRectOrder(
            //                tracker.target, event.keyCode - KC_ZERO);
            //});
        }
        this._hndl.exitHandler = function(tracker, pos, btelem, btany) {
            //$(window).unbind("keydown.setorder");
        }
        this._hndl.dragHandler = function(tracker, pos, delta, shift) {
        }

        this._hndl.releaseHandler = function(tracker, pos, insidepress, insiderelease) {
            self._viewer.activeViewer().setMouseNavEnabled(true);
            var ele = $(tracker.target),
                x0 = ele.position().left,
                y0 = ele.position().top,
                x1 = x0 + ele.width(),
                y1 = y0 + ele.height(),
                sdrect = self._normalisedRect(x0, y0, x1, y1);
            self._viewer.activeViewer().drawer.updateOverlay(tracker.target, sdrect);
        }
    },

    dragDone: function() {
        this._hndl.setTracking(true);
        this._canvas.unbind("mousemove.drawcanvas");
        this._canvas.unbind("mouseup.drawcanvas");
        this.callListeners("onCanvasChanged");
    },

    _initialiseNewDrag: function() {
        var self = this;

    },
});
<|endoftext|>


<commit_before>'use strict';

/* eslint new-cap: ["error", {"capIsNewExceptionPattern": "^Action.\w+$"}] */

const { URL } = require('url');

const { taggedSum } = require('daggy');
const fetch = require('node-fetch');
const R = require('ramda');

const { isAdmin } = require('../../stores/user');
const { managesGroup } = require('../../stores/group');
const { telegram } = require('../../bot');

const {
	excludeLinks = [],
	notifyBrokenLink,
} = require('../../config');

if (excludeLinks === false || excludeLinks === '*') {
	module.exports = (ctx, next) => next();
	return;
}

const normalizeTme = R.replace(
	/^(?:@|(?:https?:\/\/)?(?:t\.me|telegram\.(?:me|dog))\/)(\w+)(\/.+)?/i,
	(_match, username, rest) => /^\/\d+$/.test(rest)
		? `https://t.me/${username.toLowerCase()}`
		: `https://t.me/${username.toLowerCase()}${rest || ''}`
);

const customWhitelist = new Set(excludeLinks.map(normalizeTme));

const Action = taggedSum('Action', {
	Nothing: [],
	Notify: [ 'errorMsg' ],
	Warn: [ 'reason' ],
});

const cata = R.invoker(1, 'cata');
const actionPriority = cata({
	// Numbers are relative to each other
	Nothing: () => 0,
	Notify: () => 10,
	Warn: () => 20,
});
const maxByActionPriority = R.maxBy(actionPriority);
const highestPriorityAction = R.reduce(maxByActionPriority, Action.Nothing);

const assumeProtocol = R.unless(R.contains('://'), R.concat('http://'));
const conatained = R.flip(R.contains);
const constructAbsUrl = R.constructN(1, URL);
const isHttp = R.propSatisfies(R.test(/^https?:$/i), 'protocol');
const isLink = R.propSatisfies(
	conatained([ 'url', 'text_link', 'mention' ]),
	'type'
);
const memoize = R.memoizeWith(R.identity);

const domainContainedIn = R.curry((domains, url) =>
	domains.has(url.host.toLowerCase()));

const obtainUrlFromText = text => ({ length, offset, url }) =>
	url
		? url
		: text.slice(offset, length + offset);

const blacklisted = {
	protocol: url =>
		url.protocol === 'tg:' && url.host.toLowerCase() === 'resolve',
};

const isPublic = async username => {
	try {
		const chat = await telegram.getChat(username);
		return chat.type !== 'private';
	} catch (err) {
		return false;
	}
};

const dh = {
	blacklistedDomain: R.always(Action.Warn('Link to blacklisted domain')),
	nothing: R.always(Action.Nothing),
	tme: async url => {
		if (url.pathname === '/') return Action.Nothing;
		if (url.searchParams.has('start')) return Action.Warn('Bot reflink');
		if (await managesGroup({ link: url.toString() })) return Action.Nothing;
		const [ , username ] = R.match(/^\/(\w+)(?:\/\d*)?$/, url.pathname);
		if (username && !await isPublic('@' + username)) return Action.Nothing;
		return Action.Warn('Link to Telegram group or channel');
	},
};

const domainHandlers = new Map([
	[ 'chat.whatsapp.com', dh.blacklistedDomain ],
	[ 'loverdesuootnosheniya.blogspot.com', dh.blacklistedDomain ],
	[ 't.me', dh.tme ],
	[ 'telegram.dog', dh.tme ],
	[ 'telegram.me', dh.tme ],
	[ 'tinyurl.com', dh.blacklistedDomain ],
	[ 'your-sweet-dating.com', dh.blacklistedDomain ],
]);

const isWhitelisted = (url) => customWhitelist.has(url.toString());

class CodeError extends Error {
	constructor(code) {
		super(code);
		this.code = code;
	}
}

const unshorten = url =>
	fetch(url, { redirect: 'follow' }).then(res =>
		res.ok
			? new URL(normalizeTme(res.url))
			: Promise.reject(new CodeError(`${res.status} ${res.statusText}`)));

const checkLinkByDomain = url => {
	const domain = url.host.toLowerCase();
	const handler = domainHandlers.get(domain) || dh.nothing;
	return handler(url);
};

const classifyAsync = memoize(async url => {
	if (isWhitelisted(url)) return Action.Nothing;

	if (blacklisted.protocol(url)) return Action.Warn('Link using tg protocol');

	if (domainContainedIn(domainHandlers, url)) return checkLinkByDomain(url);

	if (!isHttp(url)) return Action.Nothing;

	try {
		const longUrl = await unshorten(url);
		if (isWhitelisted(longUrl)) return Action.Nothing;
		return checkLinkByDomain(longUrl);
	} catch (e) {
		e.url = url;
		return Action.Notify(e);
	}
});

const classifyList = (urls) =>
	Promise.all(urls.map(classifyAsync))
		.then(highestPriorityAction);

const matchTmeLinks = R.match(/\b(?:t\.me|telegram\.(?:me|dog))\/[\w-/]+/gi);

const classifyCtx = (ctx) => {
	if (ctx.chat.type === 'private') return Action.Nothing;

	const message = ctx.message || ctx.editedMessage;

	const entities = message.entities || message.caption_entities || [];

	const text = message.text || message.caption || '';

	const rawUrls = entities
		.filter(isLink)
		.map(obtainUrlFromText(text))
		.concat(matchTmeLinks(text));

	const urls = R.uniq(rawUrls)
		.map(normalizeTme)
		.map(assumeProtocol)
		.map(constructAbsUrl);

	return classifyList(urls);
};

module.exports = async (ctx, next) =>
	(await classifyCtx(ctx)).cata({
		Nothing: next,
		Notify(error) {
			const message = ctx.message || ctx.editedMessage;
			const reply_to_message_id = message.message_id;
			if (notifyBrokenLink) {
				ctx.reply(
					`ℹ Link ${error.url} seems to be broken (${error.code}).`,
					{ reply_to_message_id }
				);
			}
			return next();
		},
		Warn: async (reason) => {
			const admin = ctx.botInfo;
			const userToWarn = ctx.from;

			if (await isAdmin(userToWarn)) return next();

			ctx.deleteMessage();
			return ctx.warn({ admin, reason, userToWarn });
		},
	});
<commit_msg>[Bugfix] Don't warn for links to sticker packs (#75)<commit_after>'use strict';

/* eslint new-cap: ["error", {"capIsNewExceptionPattern": "^Action.\w+$"}] */

const { URL } = require('url');

const { taggedSum } = require('daggy');
const fetch = require('node-fetch');
const R = require('ramda');

const { isAdmin } = require('../../stores/user');
const { managesGroup } = require('../../stores/group');
const { telegram } = require('../../bot');

const {
	excludeLinks = [],
	notifyBrokenLink,
} = require('../../config');

if (excludeLinks === false || excludeLinks === '*') {
	module.exports = (ctx, next) => next();
	return;
}

const normalizeTme = R.replace(
	/^(?:@|(?:https?:\/\/)?(?:t\.me|telegram\.(?:me|dog))\/)(\w+)(\/.+)?/i,
	(_match, username, rest) => /^\/\d+$/.test(rest)
		? `https://t.me/${username.toLowerCase()}`
		: `https://t.me/${username.toLowerCase()}${rest || ''}`
);

const customWhitelist = new Set(excludeLinks.map(normalizeTme));

const Action = taggedSum('Action', {
	Nothing: [],
	Notify: [ 'errorMsg' ],
	Warn: [ 'reason' ],
});

const cata = R.invoker(1, 'cata');
const actionPriority = cata({
	// Numbers are relative to each other
	Nothing: () => 0,
	Notify: () => 10,
	Warn: () => 20,
});
const maxByActionPriority = R.maxBy(actionPriority);
const highestPriorityAction = R.reduce(maxByActionPriority, Action.Nothing);

const assumeProtocol = R.unless(R.contains('://'), R.concat('http://'));
const conatained = R.flip(R.contains);
const constructAbsUrl = R.constructN(1, URL);
const isHttp = R.propSatisfies(R.test(/^https?:$/i), 'protocol');
const isLink = R.propSatisfies(
	conatained([ 'url', 'text_link', 'mention' ]),
	'type'
);
const memoize = R.memoizeWith(R.identity);

const domainContainedIn = R.curry((domains, url) =>
	domains.has(url.host.toLowerCase()));

const obtainUrlFromText = text => ({ length, offset, url }) =>
	url
		? url
		: text.slice(offset, length + offset);

const blacklisted = {
	protocol: url =>
		url.protocol === 'tg:' && url.host.toLowerCase() === 'resolve',
};

const isPublic = async username => {
	try {
		const chat = await telegram.getChat(username);
		return chat.type !== 'private';
	} catch (err) {
		return false;
	}
};

const dh = {
	blacklistedDomain: R.always(Action.Warn('Link to blacklisted domain')),
	nothing: R.always(Action.Nothing),
	tme: async url => {
		if (url.pathname === '/') return Action.Nothing;
		if (url.pathname.toLowerCase().startsWith('/addstickers/')) return Action.Nothing;
		if (url.searchParams.has('start')) return Action.Warn('Bot reflink');
		if (await managesGroup({ link: url.toString() })) return Action.Nothing;
		const [ , username ] = R.match(/^\/(\w+)(?:\/\d*)?$/, url.pathname);
		if (username && !await isPublic('@' + username)) return Action.Nothing;
		return Action.Warn('Link to Telegram group or channel');
	},
};

const domainHandlers = new Map([
	[ 'chat.whatsapp.com', dh.blacklistedDomain ],
	[ 'loverdesuootnosheniya.blogspot.com', dh.blacklistedDomain ],
	[ 't.me', dh.tme ],
	[ 'telegram.dog', dh.tme ],
	[ 'telegram.me', dh.tme ],
	[ 'tinyurl.com', dh.blacklistedDomain ],
	[ 'your-sweet-dating.com', dh.blacklistedDomain ],
]);

const isWhitelisted = (url) => customWhitelist.has(url.toString());

class CodeError extends Error {
	constructor(code) {
		super(code);
		this.code = code;
	}
}

const unshorten = url =>
	fetch(url, { redirect: 'follow' }).then(res =>
		res.ok
			? new URL(normalizeTme(res.url))
			: Promise.reject(new CodeError(`${res.status} ${res.statusText}`)));

const checkLinkByDomain = url => {
	const domain = url.host.toLowerCase();
	const handler = domainHandlers.get(domain) || dh.nothing;
	return handler(url);
};

const classifyAsync = memoize(async url => {
	if (isWhitelisted(url)) return Action.Nothing;

	if (blacklisted.protocol(url)) return Action.Warn('Link using tg protocol');

	if (domainContainedIn(domainHandlers, url)) return checkLinkByDomain(url);

	if (!isHttp(url)) return Action.Nothing;

	try {
		const longUrl = await unshorten(url);
		if (isWhitelisted(longUrl)) return Action.Nothing;
		return checkLinkByDomain(longUrl);
	} catch (e) {
		e.url = url;
		return Action.Notify(e);
	}
});

const classifyList = (urls) =>
	Promise.all(urls.map(classifyAsync))
		.then(highestPriorityAction);

const matchTmeLinks = R.match(/\b(?:t\.me|telegram\.(?:me|dog))\/[\w-/]+/gi);

const classifyCtx = (ctx) => {
	if (ctx.chat.type === 'private') return Action.Nothing;

	const message = ctx.message || ctx.editedMessage;

	const entities = message.entities || message.caption_entities || [];

	const text = message.text || message.caption || '';

	const rawUrls = entities
		.filter(isLink)
		.map(obtainUrlFromText(text))
		.concat(matchTmeLinks(text));

	const urls = R.uniq(rawUrls)
		.map(normalizeTme)
		.map(assumeProtocol)
		.map(constructAbsUrl);

	return classifyList(urls);
};

module.exports = async (ctx, next) =>
	(await classifyCtx(ctx)).cata({
		Nothing: next,
		Notify(error) {
			const message = ctx.message || ctx.editedMessage;
			const reply_to_message_id = message.message_id;
			if (notifyBrokenLink) {
				ctx.reply(
					`ℹ Link ${error.url} seems to be broken (${error.code}).`,
					{ reply_to_message_id }
				);
			}
			return next();
		},
		Warn: async (reason) => {
			const admin = ctx.botInfo;
			const userToWarn = ctx.from;

			if (await isAdmin(userToWarn)) return next();

			ctx.deleteMessage();
			return ctx.warn({ admin, reason, userToWarn });
		},
	});
<|endoftext|>