<commit_before>MyHomeworkSpace.Pages.planner = {
	currentWeek: undefined,
	init: function() {
		$("#plannerPrev").click(function() {
			MyHomeworkSpace.Pages.planner.changeWeek(-1);
		});
		$("#plannerNext").click(function() {
			MyHomeworkSpace.Pages.planner.changeWeek(1);
		});
		$("#plannerWeek").tooltip();
		$("#plannerWeek").click(function() {
			$.datepicker._gotoToday = function (id) {
				$(id).datepicker('setDate', new Date());
				$('.ui-datepicker-current-day').click();
			};
			$("body").datepicker("dialog", MyHomeworkSpace.Pages.planner.currentWeek.toDate(), function(dateStr) {
				var monday = moment(dateStr);
				while (monday.day() != 1) {
					monday.subtract(1, "day");
				}
				MyHomeworkSpace.Pages.planner.loadWeek(monday);
			}, {
				showButtonPanel: true
			});
		});
	},
	changeWeek: function(direction) {
		MyHomeworkSpace.Pages.planner.currentWeek.add(7 * direction, "days");
		MyHomeworkSpace.Pages.planner.loadWeek(MyHomeworkSpace.Pages.planner.currentWeek);
	},
	loadWeek: function(monday) {
		MyHomeworkSpace.Pages.planner.currentWeek = monday;
		$("#plannerWeek").text(monday.format("M/D"));
		$("#plannerTableBody tr td ul").text("");
		$(".announcementDay").text("");
		$("#plannerFridayIndex").text("");
		// fill in days
		for (var i = 0; i < 7; i++) {
			$("#dowDay" + i).text(monday.format("M/D"));
			monday.add(1, "day");
		}

		monday.subtract(7, "days"); // reset variable

		MyHomeworkSpace.API.get("planner/getWeekInfo/" + monday.format("YYYY-MM-DD"), {}, function(xhr) {
			var announcements = xhr.responseJSON.announcements;
			var friday = xhr.responseJSON.friday;
			for (var announcementIndex in announcements) {
				var announcement = announcements[announcementIndex];
				var announcementDay = moment(announcement.date);
				var plannerDow = announcementDay.day();
				if (plannerDow == 0) {
					plannerDow = 7;
				}
				plannerDow--;
				$("#announcementDay" + plannerDow).text(announcement.text);
			}
			if (friday.id != -1) {
				$("#plannerFridayIndex").text(friday.index + " ");
			}
			MyHomeworkSpace.API.get("homework/getWeek/" + monday.format("YYYY-MM-DD"), {}, function(xhr) {
				var hw = xhr.responseJSON.homework;
				for (var hwIndex in hw) {
					var hwItem = hw[hwIndex];
					var due = moment(hwItem.due);
					var plannerDow = due.day();

					if (plannerDow == 0) {
						plannerDow = 7;
					}
					plannerDow--;

					var $item = $('

');
						$item.addClass("plannerItem");
						$item.attr("data-hwId", hwItem.id);
						$item.append($('').text(hwItem.name.split(" ")[0]).addClass(MyHomeworkSpace.Prefixes.matchClass(hwItem.name.split(" ")[0])));
						$item.append(" " + hwItem.name.substr(hwItem.name.indexOf(" ")));
						if (hwItem.complete == "1") {
							$item.addClass("done");
						}
						var $controls = $('

');
							var $done = $('');
								$done.click(function() {
									$(this).parent().parent().toggleClass("done");
									MyHomeworkSpace.Pages.homework.markComplete($(this).parent().parent().attr("data-hwId"), ($(this).parent().parent().hasClass("done") ? "1" : "0"));
								});
							$controls.append($done);
							$controls.append(" ");
							var $edit = $('');
								$edit.click(function() {
									MyHomeworkSpace.Pages.homework.edit($(this).parent().parent().attr("data-hwId"));
								});
							$controls.append($edit);
						$item.append($controls);
					$("#plannerTableBody tr[data-classId=" + hwItem.classId + "] td[data-dow=" + plannerDow + "] ul").append($item);
				}
			});
		});
	},
	open: function() {
		$("#plannerTableBody").html("");
		for (var classIndex in MyHomeworkSpace.Classes.list) {
			var classItem = MyHomeworkSpace.Classes.list[classIndex];
			var $classRow = $('

');
				$classRow.attr("data-classId", classItem.id);
				$classRow.append($('	').text(classItem.name).addClass("subjectCell"));
				$classRow.append($('

	').attr("data-dow", "0"));
				$classRow.append($('

	').attr("data-dow", "1"));
				$classRow.append($('

	').attr("data-dow", "2"));
				$classRow.append($('

	').attr("data-dow", "3"));
				$classRow.append($('

	').attr("data-dow", "4"));
				$classRow.append($('

	').attr("data-dow", "5"));
				$classRow.append($('

	').attr("data-dow", "6"));
			$("#plannerTableBody").append($classRow);
		}
		if (!MyHomeworkSpace.Pages.planner.currentWeek) {
			MyHomeworkSpace.Pages.planner.currentWeek = MyHomeworkSpace.Utils.findMonday();
		}
		MyHomeworkSpace.Pages.planner.loadWeek(MyHomeworkSpace.Pages.planner.currentWeek);
	}
};
<commit_msg>fix lack of sanitization in some planner homework entries<commit_after>MyHomeworkSpace.Pages.planner = {
	currentWeek: undefined,
	init: function() {
		$("#plannerPrev").click(function() {
			MyHomeworkSpace.Pages.planner.changeWeek(-1);
		});
		$("#plannerNext").click(function() {
			MyHomeworkSpace.Pages.planner.changeWeek(1);
		});
		$("#plannerWeek").tooltip();
		$("#plannerWeek").click(function() {
			$.datepicker._gotoToday = function (id) {
				$(id).datepicker('setDate', new Date());
				$('.ui-datepicker-current-day').click();
			};
			$("body").datepicker("dialog", MyHomeworkSpace.Pages.planner.currentWeek.toDate(), function(dateStr) {
				var monday = moment(dateStr);
				while (monday.day() != 1) {
					monday.subtract(1, "day");
				}
				MyHomeworkSpace.Pages.planner.loadWeek(monday);
			}, {
				showButtonPanel: true
			});
		});
	},
	changeWeek: function(direction) {
		MyHomeworkSpace.Pages.planner.currentWeek.add(7 * direction, "days");
		MyHomeworkSpace.Pages.planner.loadWeek(MyHomeworkSpace.Pages.planner.currentWeek);
	},
	loadWeek: function(monday) {
		MyHomeworkSpace.Pages.planner.currentWeek = monday;
		$("#plannerWeek").text(monday.format("M/D"));
		$("#plannerTableBody tr td ul").text("");
		$(".announcementDay").text("");
		$("#plannerFridayIndex").text("");
		// fill in days
		for (var i = 0; i < 7; i++) {
			$("#dowDay" + i).text(monday.format("M/D"));
			monday.add(1, "day");
		}

		monday.subtract(7, "days"); // reset variable

		MyHomeworkSpace.API.get("planner/getWeekInfo/" + monday.format("YYYY-MM-DD"), {}, function(xhr) {
			var announcements = xhr.responseJSON.announcements;
			var friday = xhr.responseJSON.friday;
			for (var announcementIndex in announcements) {
				var announcement = announcements[announcementIndex];
				var announcementDay = moment(announcement.date);
				var plannerDow = announcementDay.day();
				if (plannerDow == 0) {
					plannerDow = 7;
				}
				plannerDow--;
				$("#announcementDay" + plannerDow).text(announcement.text);
			}
			if (friday.id != -1) {
				$("#plannerFridayIndex").text(friday.index + " ");
			}
			MyHomeworkSpace.API.get("homework/getWeek/" + monday.format("YYYY-MM-DD"), {}, function(xhr) {
				var hw = xhr.responseJSON.homework;
				for (var hwIndex in hw) {
					var hwItem = hw[hwIndex];
					var due = moment(hwItem.due);
					var plannerDow = due.day();

					if (plannerDow == 0) {
						plannerDow = 7;
					}
					plannerDow--;

					var $item = $('

');
						$item.addClass("plannerItem");
						$item.attr("data-hwId", hwItem.id);
						$item.append($('').text(hwItem.name.split(" ")[0]).addClass(MyHomeworkSpace.Prefixes.matchClass(hwItem.name.split(" ")[0])));
						$item.append($('</span').text(" " + hwItem.name.substr(hwItem.name.indexOf(" "))));
						if (hwItem.complete == "1") {
							$item.addClass("done");
						}
						var $controls = $('

');
							var $done = $('');
								$done.click(function() {
									$(this).parent().parent().toggleClass("done");
									MyHomeworkSpace.Pages.homework.markComplete($(this).parent().parent().attr("data-hwId"), ($(this).parent().parent().hasClass("done") ? "1" : "0"));
								});
							$controls.append($done);
							$controls.append(" ");
							var $edit = $('');
								$edit.click(function() {
									MyHomeworkSpace.Pages.homework.edit($(this).parent().parent().attr("data-hwId"));
								});
							$controls.append($edit);
						$item.append($controls);
					$("#plannerTableBody tr[data-classId=" + hwItem.classId + "] td[data-dow=" + plannerDow + "] ul").append($item);
				}
			});
		});
	},
	open: function() {
		$("#plannerTableBody").html("");
		for (var classIndex in MyHomeworkSpace.Classes.list) {
			var classItem = MyHomeworkSpace.Classes.list[classIndex];
			var $classRow = $('

');
				$classRow.attr("data-classId", classItem.id);
				$classRow.append($('	').text(classItem.name).addClass("subjectCell"));
				$classRow.append($('

	').attr("data-dow", "0"));
				$classRow.append($('

	').attr("data-dow", "1"));
				$classRow.append($('

	').attr("data-dow", "2"));
				$classRow.append($('

	').attr("data-dow", "3"));
				$classRow.append($('

	').attr("data-dow", "4"));
				$classRow.append($('

	').attr("data-dow", "5"));
				$classRow.append($('

	').attr("data-dow", "6"));
			$("#plannerTableBody").append($classRow);
		}
		if (!MyHomeworkSpace.Pages.planner.currentWeek) {
			MyHomeworkSpace.Pages.planner.currentWeek = MyHomeworkSpace.Utils.findMonday();
		}
		MyHomeworkSpace.Pages.planner.loadWeek(MyHomeworkSpace.Pages.planner.currentWeek);
	}
};
<|endoftext|>


<commit_before>'use strict';
require('..');
const assert = require('assert');

Promise.props({
    a : Promise.resolve(1),
    b : Promise.resolve(2),
    c : Promise.resolve(3)
}).then(r => {
    assert.deepEqual(r, {
        a : 1,
        b : 2,
        c : 3
    }, 'props');
});

console.log('ok');
<commit_msg>add test for callback<commit_after>'use strict';
require('..');
const assert = require('assert');

Promise.props({
    a : Promise.resolve(1),
    b : Promise.resolve(2),
    c : Promise.resolve(3)
}).then(r => {
    assert.deepEqual(r, {
        a : 1,
        b : 2,
        c : 3
    }, 'props');
});

;(_ => {
    var cb = Promise.callback();
    cb(null, true);
    return cb.promise;
})().then(r => {
    assert.equal(r, true, 'callback #1');
});
;(_ => {
    var cb = Promise.callback();
    cb(null, 1, 2, 3, 4, 5, 6, 7);
    return cb.promise;
})().then(r => {
    assert.deepEqual(r, [1, 2, 3, 4, 5, 6, 7], 'callback #2');
});
;(_ => {
    var cb = Promise.callback();
    cb(new Error(''));
    return cb.promise;
})().then(r => {
    console.error('callback #3: not rejected!');
}).catch(r => {
    assert.equal(r instanceof Error, true, 'callback #3');
});

console.log('ok');
<|endoftext|>


<commit_before>const versioning = require('../../../../versioning');

module.exports = {
  getRollbackUpdate,
};

function getRollbackUpdate(config, versions) {
  const { packageFile, versionScheme, depName, currentValue } = config;
  const { getMajor, isLessThanRange, getNewValue, sortVersions } = versioning(
    versionScheme
  );
  // istanbul ignore if
  if (!isLessThanRange) {
    logger.info(
      { versionScheme },
      'Current version scheme does not support isLessThanRange()'
    );
    return null;
  }
  const lessThanVersions = versions.filter(version =>
    isLessThanRange(version, currentValue)
  );
  // istanbul ignore if
  if (!lessThanVersions.length) {
    logger.info(
      { packageFile, depName, currentValue },
      'Missing version has nothing to roll back to'
    );
    return null;
  }
  logger.info(
    { packageFile, depName, currentValue },
    `Current version not found - rolling back`
  );
  lessThanVersions.sort(sortVersions);
  const toVersion = lessThanVersions.pop();
  let fromVersion;
  const newValue = getNewValue(currentValue, 'replace', fromVersion, toVersion);
  return {
    type: 'rollback',
    branchName:
      '{{{branchPrefix}}}rollback-{{{depNameSanitized}}}-{{{newMajor}}}.x',
    commitMessageAction: 'Roll back',
    isRollback: true,
    newValue,
    newMajor: getMajor(toVersion),
    semanticCommitType: 'fix',
  };
}
<commit_msg>logs: print versions when rolling back<commit_after>const versioning = require('../../../../versioning');

module.exports = {
  getRollbackUpdate,
};

function getRollbackUpdate(config, versions) {
  const { packageFile, versionScheme, depName, currentValue } = config;
  const { getMajor, isLessThanRange, getNewValue, sortVersions } = versioning(
    versionScheme
  );
  // istanbul ignore if
  if (!isLessThanRange) {
    logger.info(
      { versionScheme },
      'Current version scheme does not support isLessThanRange()'
    );
    return null;
  }
  const lessThanVersions = versions.filter(version =>
    isLessThanRange(version, currentValue)
  );
  // istanbul ignore if
  if (!lessThanVersions.length) {
    logger.info(
      { packageFile, depName, currentValue },
      'Missing version has nothing to roll back to'
    );
    return null;
  }
  logger.info(
    { packageFile, depName, currentValue, versions },
    `Current version not found - rolling back`
  );
  lessThanVersions.sort(sortVersions);
  const toVersion = lessThanVersions.pop();
  let fromVersion;
  const newValue = getNewValue(currentValue, 'replace', fromVersion, toVersion);
  return {
    type: 'rollback',
    branchName:
      '{{{branchPrefix}}}rollback-{{{depNameSanitized}}}-{{{newMajor}}}.x',
    commitMessageAction: 'Roll back',
    isRollback: true,
    newValue,
    newMajor: getMajor(toVersion),
    semanticCommitType: 'fix',
  };
}
<|endoftext|>


<commit_before>// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Iplookup utility functions
 *
 * @package    moodlecore
 * @subpackage iplookup
 * @copyright  2008 Petr Skoda (http://skodak.org)
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

M.core_iplookup = {};

M.core_iplookup.init = function(Y, latitude, longitude) {
    if (GBrowserIsCompatible()) {
        var map = new GMap2(document.getElementById("map"));
        map.addControl(new GSmallMapControl());
        map.addControl(new GMapTypeControl());
        var point = new GLatLng(latitude, longitude);
        map.setCenter(point, 4);
        map.addOverlay(new GMarker(point));
        map.setMapType(G_HYBRID_MAP);

        Y.on('unload', function() {
            if (GBrowserIsCompatible()) {
                GUnload();
            }
        }, document.body);
    }
};
<commit_msg>fixed docs<commit_after>// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Iplookup utility functions
 *
 * @package    core
 * @subpackage iplookup
 * @copyright  2008 Petr Skoda (http://skodak.org)
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

M.core_iplookup = {};

M.core_iplookup.init = function(Y, latitude, longitude) {
    if (GBrowserIsCompatible()) {
        var map = new GMap2(document.getElementById("map"));
        map.addControl(new GSmallMapControl());
        map.addControl(new GMapTypeControl());
        var point = new GLatLng(latitude, longitude);
        map.setCenter(point, 4);
        map.addOverlay(new GMarker(point));
        map.setMapType(G_HYBRID_MAP);

        Y.on('unload', function() {
            if (GBrowserIsCompatible()) {
                GUnload();
            }
        }, document.body);
    }
};
<|endoftext|>


<commit_before>import { OrderedMap } from 'immutable'

import { memoize, rawValue, setRawValue } from './lowlevel/common'
import std from './std'
import { hash } from './crypto'
import Bits256 from './Bits256'

const Hash = std.resolve('Hash')

const MAP_VIEW_NODE_DEF = [
  {
    name: 'MapViewNode',
    union: [
      {
        name: 'branch',
        type: {
          struct: [
            { name: 'left', type: 'MapViewNode' },
            { name: 'right', type: 'MapViewNode' },
            { name: 'leftKey', type: 'Bits256' },
            { name: 'rightKey', type: 'Bits256' }
          ]
        }
      },
      { name: 'hash', type: 'Hash' },
      { name: 'val', type: 'T' }
    ]
  },
  {
    name: 'MapViewRoot',
    union: [
      { name: 'empty', type: 'None' },
      {
        name: 'stub',
        type: {
          struct: [
            { name: 'key', type: 'Bits256' },
            {
              name: 'value',
              type: {
                union: [
                  { name: 'hash', type: 'Hash' },
                  { name: 'val', type: 'T' }
                ]
              }
            }
          ]
        }
      },
      { name: 'tree', type: 'MapViewNode' }
    ]
  }
]

/**
 * Creates a `MapViewNode<ValType>` for a specific type of values.
 */
function mapViewRoot (ValType, resolver) {
  // XXX: works only with "native" type definitions
  return std.resolver.addNativeTypes({ Bits256, T: ValType })
    .addTypes(MAP_VIEW_NODE_DEF)
    .resolve('MapViewRoot')
}

/**
 * Walks the tree and parses the structure of a proof for MapView.
 * Throws errors if the structure is incorrect (i.e., some broken invariants).
 */
function parseTreeStructure (tree) {
  const nodes = []
  const leaves = []

  /**
   * Recursively walks the tree from root to leaves.
   */
  function walkTree (node, key = Bits256.from('')) {
    node.fullKey = key
    nodes.push(node)

    switch (node.type) {
      case 'val':
      case 'hash':
        leaves.push(node)
        break
      case 'branch':
        const { left, right, leftKey, rightKey } = node.branch

        if (key.bitLength() === 0) {
          // Root branch has the special rules as to the validity of the keys:
          // Neither of the keys should be a substring of the other key
          let pos = 0
          const maxPos = Math.min(leftKey.bitLength(), rightKey.bitLength())
          while (pos < maxPos && leftKey.bit(pos) === rightKey.bit(pos)) {
            pos++
          }
          if (pos === maxPos) {
            throw new Error('Invalid MapView: one of the keys at the root is a substring of the other key')
          }

          if (leftKey.bit(pos) > rightKey.bit(pos)) {
            throw new TypeError('Invalid MapView: Incorrect key ordering')
          }
        } else {
          // Non-root branch; left key should start with 0, and right one with 1
          if (leftKey.bit(0) !== 0 || rightKey.bit(0) !== 1) {
            throw new Error('Invalid MapView: Incorrect key ordering')
          }
        }

        // `key.append(...)` checks overflow of keys
        walkTree(left, key.append(leftKey))
        walkTree(right, key.append(rightKey))
        break
    }
  }

  walkTree(tree)
  const values = leaves.filter(node => node.type === 'val')

  // All values must have terminal keys
  if (!values.every(node => node.fullKey.isTerminal)) {
    throw new Error('Invalid MapView: non-terminal key at value node')
  }

  return { nodes, leaves, values }
}

function validateStub (stub) {
  if (!stub.key.isTerminal) {
    throw new Error('Invalid MapView: non-terminal key at an isolated node')
  }
}

/**
 * Calculates tree hash of a stub `MapView`.
 *
 * @returns {Uint8Array}
 */
function stubHash ({ key, value }) {
  const valueHash = (value.type === 'val') ? hash(value.val) : value.hash
  return hash(key, valueHash)
}

/**
 * Recursively calculates the hash of the entire `MapView`.
 *
 * @param {MapViewNode<any>} node
 * @returns {Uint8Array}
 */
function treeHash (node) {
  switch (node.type) {
    case 'hash':
      return node.hash
    case 'val':
      return hash(node.val)
    case 'branch':
      const { left, right } = node.branch
      return hash(treeHash(left), treeHash(right), left.fullKey, right.fullKey)
  }
}

const PROXIED_METHODS = [
  'keys',
  'values',
  'entries',
  'keySeq',
  'valueSeq',
  'entrySeq'
]

export default function mapView (ValType, resolver) {
  // The `Root<ValType>` class
  const Root = mapViewRoot(ValType, resolver)

  class MapView {
    constructor (obj) {
      const root = Root.from(obj)

      let mapEntries = []

      switch (root.type) {
        case 'empty':
          break
        case 'stub':
          const stub = root.stub
          validateStub(stub)
          if (stub.value.type === 'val') {
            // Initialize the tree with a single element
            mapEntries = [[stub.key.getOriginal('bytes'), stub.value.val]]
          } else {
            // No visible elements in the tree
          }
          break
        case 'tree':
          const { values } = parseTreeStructure(root.tree)
          // Guaranteed to be sorted by ascending `node.pos`
          mapEntries = values.map(node => [node.fullKey.getOriginal('bytes'), node.val])
          break
      }

      const map = OrderedMap(mapEntries)
      setRawValue(this, { root, map })
    }

    rootHash () {
      const root = rawValue(this).root

      switch (root.type) {
        case 'empty':
          return new Uint8Array(32)
        case 'stub':
          return stubHash(root.stub)
        case 'tree':
          return treeHash(root.tree)
      }
    }

    count () {
      return rawValue(this).map.count()
    }

    has (hash) {
      const map = rawValue(this).map
      return map.has(Hash.from(hash))
    }

    get (hash) {
      const map = rawValue(this).map
      return map.get(Hash.from(hash))
    }
  }

  MapView.prototype.rootHash = memoize(MapView.prototype.rootHash)

  PROXIED_METHODS.forEach(methodName => {
    MapView.prototype[methodName] = function () {
      const map = rawValue(this).map.mapKeys(k => rawValue(k, true))
      return map[methodName].apply(map, arguments)
    }
  })

  return MapView
}
<commit_msg>Implement checks for potential keys in `MapView`<commit_after>import { OrderedMap } from 'immutable'

import { memoize, rawValue, setRawValue } from './lowlevel/common'
import std from './std'
import { hash } from './crypto'
import Bits256, { getBit } from './Bits256'

const Hash = std.resolve('Hash')

const MAP_VIEW_NODE_DEF = [
  {
    name: 'MapViewNode',
    union: [
      {
        name: 'branch',
        type: {
          struct: [
            { name: 'left', type: 'MapViewNode' },
            { name: 'right', type: 'MapViewNode' },
            { name: 'leftKey', type: 'Bits256' },
            { name: 'rightKey', type: 'Bits256' }
          ]
        }
      },
      { name: 'hash', type: 'Hash' },
      { name: 'val', type: 'T' }
    ]
  },
  {
    name: 'MapViewRoot',
    union: [
      { name: 'empty', type: 'None' },
      {
        name: 'stub',
        type: {
          struct: [
            { name: 'key', type: 'Bits256' },
            {
              name: 'value',
              type: {
                union: [
                  { name: 'hash', type: 'Hash' },
                  { name: 'val', type: 'T' }
                ]
              }
            }
          ]
        }
      },
      { name: 'tree', type: 'MapViewNode' }
    ]
  }
]

/**
 * Creates a `MapViewNode<ValType>` for a specific type of values.
 */
function mapViewRoot (ValType, resolver) {
  // XXX: works only with "native" type definitions
  return std.resolver.addNativeTypes({ Bits256, T: ValType })
    .addTypes(MAP_VIEW_NODE_DEF)
    .resolve('MapViewRoot')
}

/**
 * Walks the tree and parses the structure of a proof for MapView.
 * Throws errors if the structure is incorrect (i.e., some broken invariants).
 */
function parseTreeStructure (tree) {
  const nodes = []
  const leaves = []

  /**
   * Recursively walks the tree from root to leaves.
   */
  function walkTree (node, key = Bits256.from('')) {
    node.fullKey = key
    nodes.push(node)

    switch (node.type) {
      case 'val':
      case 'hash':
        leaves.push(node)
        break
      case 'branch':
        const { left, right, leftKey, rightKey } = node.branch

        if (key.bitLength() === 0) {
          // Root branch has the special rules as to the validity of the keys:
          // Neither of the keys should be a substring of the other key
          let pos = 0
          const maxPos = Math.min(leftKey.bitLength(), rightKey.bitLength())
          while (pos < maxPos && leftKey.bit(pos) === rightKey.bit(pos)) {
            pos++
          }
          if (pos === maxPos) {
            throw new Error('Invalid MapView: one of the keys at the root is a substring of the other key')
          }

          if (leftKey.bit(pos) > rightKey.bit(pos)) {
            throw new TypeError('Invalid MapView: Incorrect key ordering')
          }
        } else {
          // Non-root branch; left key should start with 0, and right one with 1
          if (leftKey.bit(0) !== 0 || rightKey.bit(0) !== 1) {
            throw new Error('Invalid MapView: Incorrect key ordering')
          }
        }

        // `key.append(...)` checks overflow of keys
        walkTree(left, key.append(leftKey))
        walkTree(right, key.append(rightKey))
        break
    }
  }

  walkTree(tree)
  const values = leaves.filter(node => node.type === 'val')

  // All values must have terminal keys
  if (!values.every(node => node.fullKey.isTerminal)) {
    throw new Error('Invalid MapView: non-terminal key at value node')
  }

  return { nodes, leaves, values }
}

function validateStub (stub) {
  if (!stub.key.isTerminal) {
    throw new Error('Invalid MapView: non-terminal key at an isolated node')
  }
}

/**
 * Calculates tree hash of a stub `MapView`.
 *
 * @returns {Uint8Array}
 */
function stubHash ({ key, value }) {
  const valueHash = (value.type === 'val') ? hash(value.val) : value.hash
  return hash(key, valueHash)
}

/**
 * Recursively calculates the hash of the entire `MapView`.
 *
 * @param {MapViewNode<any>} node
 * @returns {Uint8Array}
 */
function treeHash (node) {
  switch (node.type) {
    case 'hash':
      return node.hash
    case 'val':
      return hash(node.val)
    case 'branch':
      const { left, right } = node.branch
      return hash(treeHash(left), treeHash(right), left.fullKey, right.fullKey)
  }
}

/**
 * Searches for a (hash) key in a tree-like proof for the `MapView`.
 *
 * @returns {boolean}
 *   `true` if the tree *may* continue the searched key, `false` otherwise
 */
function searchKey (node, key) {
  let pos = 0

  while (node.type === 'branch') {
    const { left, right, leftKey, rightKey } = node.branch

    let i = 0
    while (leftKey.bit(i) === getBit(key, pos + i) && rightKey.bit(i) === getBit(key, pos + i)) {
      i++ // May only be triggered for the root branch
    }

    // Are the both keys different from our key? If yes, our key is not in the tree
    if (
      pos === 0 &&
      leftKey.bit(i) === rightKey.bit(i) &&
      leftKey.bit(i) !== getBit(key, i)
    ) {
      return false
    }

    // `leftKey` and `rightKey` cannot be both exhausted here
    // because otherwise they would be the same

    let path
    let pathKey
    if (leftKey.bitLength() < i || leftKey.bit(i) === getBit(key, pos + i)) {
      [path, pathKey] = [left, leftKey]
    } else if (rightKey.bitLength() < i || rightKey.bit(i) === getBit(key, pos + i)) {
      [path, pathKey] = [right, rightKey]
    } else {
      /* istanbul ignore next: seems to be unreachable */
      throw new Error('Invariant broken: Bogus execution path in searching a key in MapView')
    }

    // Go down the path until it is exhausted or there is a discrepancy among keys
    while (i < pathKey.bitLength() && pathKey.bit(i) === getBit(key, pos + i)) {
      i++
    }

    if (i >= pathKey.bitLength()) {
      pos += pathKey.bitLength()
      node = path
    } else {
      return false
    }
  }

  // node.type !== 'branch', there is or may be a specified key
  return true
}

const PROXIED_METHODS = [
  'keys',
  'values',
  'entries',
  'keySeq',
  'valueSeq',
  'entrySeq'
]

export default function mapView (ValType, resolver) {
  // The `Root<ValType>` class
  const Root = mapViewRoot(ValType, resolver)

  class MapView {
    constructor (obj) {
      const root = Root.from(obj)

      let mapEntries = []

      switch (root.type) {
        case 'empty':
          break
        case 'stub':
          const stub = root.stub
          validateStub(stub)
          if (stub.value.type === 'val') {
            // Initialize the tree with a single element
            mapEntries = [[stub.key.getOriginal('bytes'), stub.value.val]]
          } else {
            // No visible elements in the tree
          }
          break
        case 'tree':
          const { values } = parseTreeStructure(root.tree)
          // Guaranteed to be sorted by ascending `node.pos`
          mapEntries = values.map(node => [node.fullKey.getOriginal('bytes'), node.val])
          break
      }

      const map = OrderedMap(mapEntries)
      setRawValue(this, { root, map })
    }

    rootHash () {
      const root = rawValue(this).root

      switch (root.type) {
        case 'empty':
          return new Uint8Array(32)
        case 'stub':
          return stubHash(root.stub)
        case 'tree':
          return treeHash(root.tree)
      }
    }

    count () {
      return rawValue(this).map.count()
    }

    has (hash) {
      const map = rawValue(this).map
      return map.has(Hash.from(hash))
    }

    get (hash) {
      const map = rawValue(this).map
      return map.get(Hash.from(hash))
    }

    /**
     * Checks whether this map can contain a key matching the specified hash.
     */
    mayHave (hash) {
      const root = rawValue(this).root

      switch (root.type) {
        case 'empty':
          return false
        case 'stub':
          return Hash.from(hash).equals(root.stub.key.getOriginal('bytes'))
        case 'tree':
          return searchKey(root.tree, rawValue(Hash.from(hash)))
      }
    }
  }

  MapView.prototype.rootHash = memoize(MapView.prototype.rootHash)

  PROXIED_METHODS.forEach(methodName => {
    MapView.prototype[methodName] = function () {
      const map = rawValue(this).map.mapKeys(k => rawValue(k, true))
      return map[methodName].apply(map, arguments)
    }
  })

  return MapView
}
<|endoftext|>


<commit_before>// @flow
import React, { Component } from 'react';
import { type Store } from 'redux';
import {
  localizeReducer,
  getActiveLanguage,
  getOptions,
  getTranslationsForActiveLanguage,
  type LocalizeState,
  type Action
} from './localize';
import {
  LocalizeContext,
  type LocalizeContextProps,
  getContextPropsFromState
} from './LocalizeContext';
import { storeDidChange } from './utils';

type LocalizeProviderState = {
  localize: LocalizeState
};

export type LocalizeProviderProps = {
  store?: Store<any, any>,
  children: any
};

export class LocalizeProvider extends Component<
  LocalizeProviderProps,
  LocalizeProviderState
> {
  unsubscribeFromStore: Function;
  getContextPropsSelector: any;
  contextProps: LocalizeContextProps;

  constructor(props: LocalizeProviderProps) {
    super(props);

    const dispatch = this.props.store
      ? this.props.store.dispatch
      : this.dispatch.bind(this);

    this.getContextPropsSelector = getContextPropsFromState(dispatch);

    this.state = {
      localize: localizeReducer(undefined, ({}: any))
    };
  }

  static getDerivedStateFromProps(nextProps: any, nextState: any) {
    return null;
  }

  componentDidMount() {
    if (this.props.store) {
      this.unsubscribeFromStore = storeDidChange(
        this.props.store,
        this.onStateDidChange.bind(this)
      );
    }
  }

  componentWillUnmount() {
    this.unsubscribeFromStore && this.unsubscribeFromStore();
  }

  onStateDidChange(prevState: LocalizeProviderState) {
    if (!this.props.store) {
      return;
    }

    const prevLocalizeState = prevState && prevState.localize;
    const curLocalizeState = this.props.store.getState().localize;

    const prevActiveLanguage =
      prevState && getActiveLanguage(prevLocalizeState);
    const curActiveLanguage = getActiveLanguage(curLocalizeState);

    const prevOptions = prevState && getOptions(prevLocalizeState);
    const curOptions = getOptions(curLocalizeState);

    const prevTranslations =
      prevState && getTranslationsForActiveLanguage(prevLocalizeState);
    const curTranslations = getTranslationsForActiveLanguage(curLocalizeState);

    const hasActiveLangaugeChanged =
      (prevActiveLanguage && prevActiveLanguage.code) !==
      (curActiveLanguage && curActiveLanguage.code);
    const hasOptionsChanged = prevOptions !== curOptions;
    const hasTranslationsChanged = prevTranslations !== curTranslations;

    if (
      hasActiveLangaugeChanged ||
      hasOptionsChanged ||
      hasTranslationsChanged
    ) {
      this.setState({ localize: curLocalizeState });
    }
  }

  dispatch(action: any) {
    console.log('action', action);

    this.setState(prevState => {
      return {
        localize: localizeReducer(prevState.localize, action)
      };
    });
  }

  render() {
    this.contextProps = this.getContextPropsSelector(this.state.localize);

    return (
      <LocalizeContext.Provider value={this.contextProps}>
        {this.props.children}
      </LocalizeContext.Provider>
    );
  }
}
<commit_msg>remove stray console.log<commit_after>// @flow
import React, { Component } from 'react';
import { type Store } from 'redux';
import {
  localizeReducer,
  getActiveLanguage,
  getOptions,
  getTranslationsForActiveLanguage,
  type LocalizeState,
  type Action
} from './localize';
import {
  LocalizeContext,
  type LocalizeContextProps,
  getContextPropsFromState
} from './LocalizeContext';
import { storeDidChange } from './utils';

type LocalizeProviderState = {
  localize: LocalizeState
};

export type LocalizeProviderProps = {
  store?: Store<any, any>,
  children: any
};

export class LocalizeProvider extends Component<
  LocalizeProviderProps,
  LocalizeProviderState
> {
  unsubscribeFromStore: Function;
  getContextPropsSelector: any;
  contextProps: LocalizeContextProps;

  constructor(props: LocalizeProviderProps) {
    super(props);

    const dispatch = this.props.store
      ? this.props.store.dispatch
      : this.dispatch.bind(this);

    this.getContextPropsSelector = getContextPropsFromState(dispatch);

    this.state = {
      localize: localizeReducer(undefined, ({}: any))
    };
  }

  static getDerivedStateFromProps(nextProps: any, nextState: any) {
    return null;
  }

  componentDidMount() {
    if (this.props.store) {
      this.unsubscribeFromStore = storeDidChange(
        this.props.store,
        this.onStateDidChange.bind(this)
      );
    }
  }

  componentWillUnmount() {
    this.unsubscribeFromStore && this.unsubscribeFromStore();
  }

  onStateDidChange(prevState: LocalizeProviderState) {
    if (!this.props.store) {
      return;
    }

    const prevLocalizeState = prevState && prevState.localize;
    const curLocalizeState = this.props.store.getState().localize;

    const prevActiveLanguage =
      prevState && getActiveLanguage(prevLocalizeState);
    const curActiveLanguage = getActiveLanguage(curLocalizeState);

    const prevOptions = prevState && getOptions(prevLocalizeState);
    const curOptions = getOptions(curLocalizeState);

    const prevTranslations =
      prevState && getTranslationsForActiveLanguage(prevLocalizeState);
    const curTranslations = getTranslationsForActiveLanguage(curLocalizeState);

    const hasActiveLangaugeChanged =
      (prevActiveLanguage && prevActiveLanguage.code) !==
      (curActiveLanguage && curActiveLanguage.code);
    const hasOptionsChanged = prevOptions !== curOptions;
    const hasTranslationsChanged = prevTranslations !== curTranslations;

    if (
      hasActiveLangaugeChanged ||
      hasOptionsChanged ||
      hasTranslationsChanged
    ) {
      this.setState({ localize: curLocalizeState });
    }
  }

  dispatch(action: any) {
    this.setState(prevState => {
      return {
        localize: localizeReducer(prevState.localize, action)
      };
    });
  }

  render() {
    this.contextProps = this.getContextPropsSelector(this.state.localize);

    return (
      <LocalizeContext.Provider value={this.contextProps}>
        {this.props.children}
      </LocalizeContext.Provider>
    );
  }
}
<|endoftext|>


<commit_before>/*
* Copyright (C) 2012 by CoNarrative
*/
/**
 * @class glu.extjs.adapters.panel
 * @author Mike Gai, Nick Tackes, Travis Barajas
 * @extends glu.extjs.adapters.container
 * A basic adapter for all things panel.
 *
 *
 */
glu.regAdapter('panel', {
    extend : 'container',
    applyConventions : function(config, viewmodel) {
        Ext.applyIf(config, {
            collapsed : glu.conventions.expression(config.name + 'IsExpanded', {
                optional : true,
                not : true
            })
        });
        glu.provider.adapters.Container.prototype.applyConventions.apply(this, arguments);
    },

    isChildArray : function(propName, value) {
        return propName=='editors' || propName === 'items' || propName === 'dockedItems';
    },

    isChildObject : function(propName) {
        return propName === 'tbar' || propName === 'bbar' || propName === 'buttons' || propName === 'fbar' || propName === 'lbar' || propName === 'rbar';
    },

    tbarShortcut : function(value) {
        return {
            xtype : 'toolbar',
            defaultType : 'button',
            items : value,
            dock : 'top'
        }
    },

    bbarShortcut : function(value) {
        return {
            xtype : 'toolbar',
            defaultType : 'button',
            items : value,
            dock : 'bottom'
        }
    },

    buttonsShortcut : function(value) {
        return {
            xtype : 'toolbar',
            defaultType : 'button',
            items : value,
            dock : 'bottom',
            layout : {
                // default to 'end' (right-aligned)
                pack : 'end'
            }
        }
    },

    fbarShortcut : function(value) {
        return {
            xtype : 'toolbar',
            defaultType : 'button',
            items : value,
            dock : 'bottom',
            layout : {
                // default to 'end' (right-aligned)
                pack : 'end'
            }
        }
    },

    lbarShortcut : function(value) {
        return {
            xtype : 'toolbar',
            defaultType : 'button',
            items : value,
            vertical : true,
            dock : 'left'
        }
    },

    rbarShortcut : function(value) {
        return {
            xtype : 'toolbar',
            defaultType : 'button',
            items : value,
            vertical : true,
            dock : 'right'
        }
    },
    /**
     * @cfg {Function} closeHandler
     * The handle to process a 'close me' request from either a window close button or a tab close button.
     * By default it will call the 'close' method on the view model.
     * If you override the close method, use the doClose()
     * method on the view model to actually perform the close operation. To veto a close because the screen is not
     * valid would look like this:
     *      //view model assuming using default {@close} binding
     *      close : function() {
     *          if (this.isValid) {
     *              this.doClose();
     *          }
     *      }
     * Default: '{@close}'
     */
    beforeCollect : function(config) {
        glu.provider.adapters.Container.prototype.beforeCollect.apply(this, arguments);
        this.checkForEditors(config, {title: function(control){return control.header.titleCmp.textEl;}});
        //auto-add the close listener
        config.closeHandler = config.closeHandler || '@{close}';
    },
    beforeCreate : function(config, vm) {
        config.listeners = config.listeners || {};
        //The ExtJS close cycle is too strange and must be normalized
        //Now it will simply create a close request instead of anything funny...
        config.listeners.beforeclose = config.listeners.beforeclose ||
        function(panel) {
            // config.closeTask = config.closeTask || new Ext.util.DelayedTask();
            // config.closeTask.delay(1,function(){
            // panel.fireEvent('closerequest', this);
            // });
            if (config.closeHandler) {
                config.closeHandler.apply(vm);
            }
            return false;
        };

    },
    afterCreate : function(control, viewmodel) {
        glu.provider.adapters.Container.prototype.afterCreate.apply(this, arguments);
        //make sure windows close themselves when their matching view model closes...
        if (Ext.isFunction(control.close)) {
            viewmodel.on('closed', function() {
                glu.log.debug('closed matching window since viewmodel was closed');
                if (control.hidden) {
                    control.doClose();
                } else {
                    control.hide(null, control.doClose, control);
                }
            });
        }
        var expandOrCollapseFactory = function(expanded) {
            return function(control) {
                if( control.supressCollapseEvents )
                    return true;
                control.fireEvent('expandorcollapserequest', control, expanded);
                return false;
            }
        };

        if( control._bindingMap.collapsed ){
            control.on('beforecollapse', expandOrCollapseFactory(false));
            control.on('beforeexpand', expandOrCollapseFactory(true));
        }

        if (control._bindingMap && control._bindingMap.activeItem!==undefined) {
            control.addActual = control.add;
            control.add = function(index, item) {
                item.on('render', function() {
                    item.getEl().on('click', function() {
                        control.fireEvent('activeitemchangerequest', control, control.items.indexOf(item), item);
                    });
                });
                control.addActual(index, item);
            }
        }
    },
    /**
     * @cfg {String} html
     * *one-way binding.* The inner html to place in the body
     */
    htmlBindings : {
        setComponentProperty : function(value, oldValue, options, control) {
            // if the value is an object
            control.update(value);
        }
    },
    dataBindings : {
        setComponentProperty : function(value, oldValue, options, control) {//TODO: should really be the html property
            // if the value is an object
            control.update(value);
        }
    },

    /**
     * @cfg {Boolean} html
     * *one-way binding.* Whether or not the panel is collapsed.
     * Since there is a collapsed tool, we will support two-way binding in the future.
     *
     * **Convention:** @{*foo*IsCollapsed}
     */
    collapsedBindings : {
        eventName : 'expandorcollapserequest',
        eventConverter : function(control, expanded) {
            return !expanded;
        },
        storeValueInComponentAs : 'collapsedActual',
        setComponentProperty : function(value, oldValue, options, control) {
            control.supressCollapseEvents = true;
            if (value == true) {
                if (control.rendered) {
                    control.collapse(control.collapseDirection, control.animCollapse);
                } else {
                    control.collapsed = true;
                }
            } else {
                if (control.rendered) {
                    //hack for ext 4...
                    control.expand(control.animCollapse);
                } else {
                    control.collapsed = false;
                }
            }
            control.supressCollapseEvents = false;
        }
    },

    /**
     * @cfg closable
     * *one-time binding ExtJS 3.x, one-way binding ExtJS 4.x*
     */
    closableBindings : {
        setComponentProperty : function(value, oldValue, options, control) {
            if (!(Ext.getVersion().major > 3)) return;
            if (control.tab) {
                //for a panel in a tab panel
                control.tab.setClosable(value);
                return;
            }
            if (control.header) {
                for (var i =0;i<control.header.items.getCount();i++){
                    var tool = control.header.items.getAt(i);
                    if (tool.type === 'close') {
                        tool.setVisible(value);
                        return;
                    }
                }
                //couldn't find it so add if true
                if (value===true) {
                    control.addClsWithUI('closable');
                    control.addTool({
                        type: 'close',
                        handler: Ext.Function.bind(control.close, control, [])
                    });
                }
            }
        }
    },

    activeItemBindings : {
        eventName:'activeitemchangerequest',
        eventConverter:function (control, idx, item) {
            return control._activeItemValueType==='viewmodel'?item._vm:idx;
        },
        storeValueInComponentAs : '_activeIndex',
        setComponentProperty:function (value, oldValue, options, control) {
            if (value===undefined || value===-1) {
                return; //nothing to do ... can't really "deselect" within ExtJS
            }
            if (value.mtype) {
                if (value.parentList === undefined) {
                    throw "Attempted to set an activeItem to a view model that is not in a list";
                }
                control._activeItemValueType = 'viewmodel';
                control._parentList = value.parentList;
                //look up index...
                value = value.parentList.indexOf(value);
            }
            var oldItem = oldValue==-1?null : control.items.getAt(oldValue);
            control._changeOriginatedFromModel = true;
            if( control.getLayout().type == 'card')
                control.getLayout().setActiveItem(value);
            else
                control.fireEvent('activeitemchanged', control, control.items.getAt(value), oldItem);
        },
        transformInitialValue : function (value, config, viewmodel){
            if (value.mtype) {
                if (value.parentList === undefined) {
                    throw "Attempted to set an activeTab to a view model that is not in a list";
                }
                return value.parentList.indexOf(value);
            }
            return value;
        }
    },

    //TODO: Move into change tracked panel!!! BUt right now transformers don't supply bindings...
    enableTrackingBindings : {
        setComponentProperty : function(value, oldValue, options, control) {
            var idx = value ? 0 : 1;
            var active = control.items.get(idx);
            if (control.rendered) {
                control.getLayout().setActiveItem(active);
            } else {
                control.activeItem = active;
            }
        }
    },
    itemsBindings : {
        custom : function(context) {
            if (context.control.layout != 'card') {
                //do regular bindings
                glu.provider.itemsHelper.bindItems(context, true);
                return;
            }

            var activator = context.viewmodel.get(context.binding.modelPropName);
            var cardPanel = context.control;

            glu.provider.itemsHelper.bindItems(context);
        }
    }
});
<commit_msg>Adapters:  Added tpl bindings to panel adapter.<commit_after>/*
* Copyright (C) 2012 by CoNarrative
*/
/**
 * @class glu.extjs.adapters.panel
 * @author Mike Gai, Nick Tackes, Travis Barajas
 * @extends glu.extjs.adapters.container
 * A basic adapter for all things panel.
 *
 *
 */
glu.regAdapter('panel', {
    extend : 'container',
    applyConventions : function(config, viewmodel) {
        Ext.applyIf(config, {
            collapsed : glu.conventions.expression(config.name + 'IsExpanded', {
                optional : true,
                not : true
            })
        });
        glu.provider.adapters.Container.prototype.applyConventions.apply(this, arguments);
    },

    isChildArray : function(propName, value) {
        return propName=='editors' || propName === 'items' || propName === 'dockedItems';
    },

    isChildObject : function(propName) {
        return propName === 'tbar' || propName === 'bbar' || propName === 'buttons' || propName === 'fbar' || propName === 'lbar' || propName === 'rbar';
    },

    tbarShortcut : function(value) {
        return {
            xtype : 'toolbar',
            defaultType : 'button',
            items : value,
            dock : 'top'
        }
    },

    bbarShortcut : function(value) {
        return {
            xtype : 'toolbar',
            defaultType : 'button',
            items : value,
            dock : 'bottom'
        }
    },

    buttonsShortcut : function(value) {
        return {
            xtype : 'toolbar',
            defaultType : 'button',
            items : value,
            dock : 'bottom',
            layout : {
                // default to 'end' (right-aligned)
                pack : 'end'
            }
        }
    },

    fbarShortcut : function(value) {
        return {
            xtype : 'toolbar',
            defaultType : 'button',
            items : value,
            dock : 'bottom',
            layout : {
                // default to 'end' (right-aligned)
                pack : 'end'
            }
        }
    },

    lbarShortcut : function(value) {
        return {
            xtype : 'toolbar',
            defaultType : 'button',
            items : value,
            vertical : true,
            dock : 'left'
        }
    },

    rbarShortcut : function(value) {
        return {
            xtype : 'toolbar',
            defaultType : 'button',
            items : value,
            vertical : true,
            dock : 'right'
        }
    },
    /**
     * @cfg {Function} closeHandler
     * The handle to process a 'close me' request from either a window close button or a tab close button.
     * By default it will call the 'close' method on the view model.
     * If you override the close method, use the doClose()
     * method on the view model to actually perform the close operation. To veto a close because the screen is not
     * valid would look like this:
     *      //view model assuming using default {@close} binding
     *      close : function() {
     *          if (this.isValid) {
     *              this.doClose();
     *          }
     *      }
     * Default: '{@close}'
     */
    beforeCollect : function(config) {
        glu.provider.adapters.Container.prototype.beforeCollect.apply(this, arguments);
        this.checkForEditors(config, {title: function(control){return control.header.titleCmp.textEl;}});
        //auto-add the close listener
        config.closeHandler = config.closeHandler || '@{close}';
    },
    beforeCreate : function(config, vm) {
        config.listeners = config.listeners || {};
        //The ExtJS close cycle is too strange and must be normalized
        //Now it will simply create a close request instead of anything funny...
        config.listeners.beforeclose = config.listeners.beforeclose ||
        function(panel) {
            // config.closeTask = config.closeTask || new Ext.util.DelayedTask();
            // config.closeTask.delay(1,function(){
            // panel.fireEvent('closerequest', this);
            // });
            if (config.closeHandler) {
                config.closeHandler.apply(vm);
            }
            return false;
        };

    },
    afterCreate : function(control, viewmodel) {
        glu.provider.adapters.Container.prototype.afterCreate.apply(this, arguments);
        //make sure windows close themselves when their matching view model closes...
        if (Ext.isFunction(control.close)) {
            viewmodel.on('closed', function() {
                glu.log.debug('closed matching window since viewmodel was closed');
                if (control.hidden) {
                    control.doClose();
                } else {
                    control.hide(null, control.doClose, control);
                }
            });
        }
        var expandOrCollapseFactory = function(expanded) {
            return function(control) {
                if( control.supressCollapseEvents )
                    return true;
                control.fireEvent('expandorcollapserequest', control, expanded);
                return false;
            }
        };

        if( control._bindingMap.collapsed ){
            control.on('beforecollapse', expandOrCollapseFactory(false));
            control.on('beforeexpand', expandOrCollapseFactory(true));
        }

        if (control._bindingMap && control._bindingMap.activeItem!==undefined) {
            control.addActual = control.add;
            control.add = function(index, item) {
                item.on('render', function() {
                    item.getEl().on('click', function() {
                        control.fireEvent('activeitemchangerequest', control, control.items.indexOf(item), item);
                    });
                });
                control.addActual(index, item);
            }
        }
    },
    /**
     * @cfg {String} html
     * *one-way binding.* The inner html to place in the body
     */
    htmlBindings : {
        setComponentProperty : function(value, oldValue, options, control) {
            // if the value is an object
            control.update(value);
        }
    },
    dataBindings : {
        setComponentProperty : function(value, oldValue, options, control) {//TODO: should really be the html property
            // if the value is an object
            control.update(value);
        }
    },
    tplBindings : {
        setComponentProperty : function(value, oldValue, options, control) {
            // if the value is an object
            var template = new Ext.XTemplate(value);
            control.tpl = template;
        }
    },

    /**
     * @cfg {Boolean} html
     * *one-way binding.* Whether or not the panel is collapsed.
     * Since there is a collapsed tool, we will support two-way binding in the future.
     *
     * **Convention:** @{*foo*IsCollapsed}
     */
    collapsedBindings : {
        eventName : 'expandorcollapserequest',
        eventConverter : function(control, expanded) {
            return !expanded;
        },
        storeValueInComponentAs : 'collapsedActual',
        setComponentProperty : function(value, oldValue, options, control) {
            control.supressCollapseEvents = true;
            if (value == true) {
                if (control.rendered) {
                    control.collapse(control.collapseDirection, control.animCollapse);
                } else {
                    control.collapsed = true;
                }
            } else {
                if (control.rendered) {
                    //hack for ext 4...
                    control.expand(control.animCollapse);
                } else {
                    control.collapsed = false;
                }
            }
            control.supressCollapseEvents = false;
        }
    },

    /**
     * @cfg closable
     * *one-time binding ExtJS 3.x, one-way binding ExtJS 4.x*
     */
    closableBindings : {
        setComponentProperty : function(value, oldValue, options, control) {
            if (!(Ext.getVersion().major > 3)) return;
            if (control.tab) {
                //for a panel in a tab panel
                control.tab.setClosable(value);
                return;
            }
            if (control.header) {
                for (var i =0;i<control.header.items.getCount();i++){
                    var tool = control.header.items.getAt(i);
                    if (tool.type === 'close') {
                        tool.setVisible(value);
                        return;
                    }
                }
                //couldn't find it so add if true
                if (value===true) {
                    control.addClsWithUI('closable');
                    control.addTool({
                        type: 'close',
                        handler: Ext.Function.bind(control.close, control, [])
                    });
                }
            }
        }
    },

    activeItemBindings : {
        eventName:'activeitemchangerequest',
        eventConverter:function (control, idx, item) {
            return control._activeItemValueType==='viewmodel'?item._vm:idx;
        },
        storeValueInComponentAs : '_activeIndex',
        setComponentProperty:function (value, oldValue, options, control) {
            if (value===undefined || value===-1) {
                return; //nothing to do ... can't really "deselect" within ExtJS
            }
            if (value.mtype) {
                if (value.parentList === undefined) {
                    throw "Attempted to set an activeItem to a view model that is not in a list";
                }
                control._activeItemValueType = 'viewmodel';
                control._parentList = value.parentList;
                //look up index...
                value = value.parentList.indexOf(value);
            }
            var oldItem = oldValue==-1?null : control.items.getAt(oldValue);
            control._changeOriginatedFromModel = true;
            if( control.getLayout().type == 'card')
                control.getLayout().setActiveItem(value);
            else
                control.fireEvent('activeitemchanged', control, control.items.getAt(value), oldItem);
        },
        transformInitialValue : function (value, config, viewmodel){
            if (value.mtype) {
                if (value.parentList === undefined) {
                    throw "Attempted to set an activeTab to a view model that is not in a list";
                }
                return value.parentList.indexOf(value);
            }
            return value;
        }
    },

    //TODO: Move into change tracked panel!!! BUt right now transformers don't supply bindings...
    enableTrackingBindings : {
        setComponentProperty : function(value, oldValue, options, control) {
            var idx = value ? 0 : 1;
            var active = control.items.get(idx);
            if (control.rendered) {
                control.getLayout().setActiveItem(active);
            } else {
                control.activeItem = active;
            }
        }
    },
    itemsBindings : {
        custom : function(context) {
            if (context.control.layout != 'card') {
                //do regular bindings
                glu.provider.itemsHelper.bindItems(context, true);
                return;
            }

            var activator = context.viewmodel.get(context.binding.modelPropName);
            var cardPanel = context.control;

            glu.provider.itemsHelper.bindItems(context);
        }
    }
});
<|endoftext|>


<commit_before>/*
 Copyright 2019 - 2020 by Jan Dockx

 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.
 */

/* eslint-env mocha */

'use strict'

const Contract = require('../lib/IV/Contract')
const cases = require('./_cases')
const testUtil = require('./_util/testUtil')

const contract = new Contract({ pre: [cases.intentionallyFailingFunction] })

describe('mocha this', function () {
  before(function () {
    this.subject = contract.implementation(function () {})
  })

  it('works when a precondition violation occurs when a function is called with a mocha fixture as this', function () {
    // noinspection JSUnresolvedVariable
    if (this.test.intellij_test_node) {
      /* NOTE: This tests the workaround for a bug, that only occurs when running tests in IntelliJ, because of an
               unhandled circular structure in `this.test.intellij_test_node`. Eventually, Node util.inspect
               is called, and that cannot handle circular object structure in Node < 12. This test this is only
               sensible when in the context where the bug might occur. util.inspect was made more robust in Node 12,
               and now can deal with circular structures, so the bug does not appear in Node 12 or later.
               Since we still support Node 8 and 10, we need to keep this test until that has passed. */
      // MUDO only run the test in intellij, when using node < 12
      try {
        this.subject()
        true.should.be.false()
      } catch (err) {
        // logging the error produces the same problem, because console.log uses util.inspect too
        testUtil.log('' + err)
        const details = err.getDetails()
        testUtil.log(details)
        details.should.match(/𝕋⚖ \[\[failed to represent the value]]/)
        details.should.match(/\(Converting circular structure to JSON\)/)
        testUtil.log()
      }
    } else {
      testUtil.log(
        'skipping a test that verifies the workaround to a bug that only occurs in IntelliJ or with mocha-reporter'
      )
    }
  })
})

/* Mocha Context has ctx.customInspect = true
 * The problem is in
 * node_modules/mocha/lib/runnable.js, line 231:
 *
 * /**
 *  * Inspect the runnable void of private properties.
 *  *
 *  * @private
 *  * @return {string}
 *  *-
 *  Runnable.prototype.inspect = function() {
 *    return JSON.stringify(
 *      this,
 *      function(key, val) {
 *        if (key[0] === '_') {
 *          return;
 *        }
 *        if (key === 'parent') {
 *          return '#<Suite>';
 *        }
 *        if (key === 'ctx') {
 *          return '#<Context>';
 *        }
 *        return val;
 *      },
 *      2
 *    );
 *  };
 *
 * `this ` still contains circular structures, apart from what the replacer handles.
 * this.ctx.test === this, but that should be handled by the replacer
 * this.parent.ctx.test === this, but that should be handled by the replacer
 *
 * There seems to be nothing else that can make this happen, except for `this.intellij_test_node`. This seems to be
 * added on by IntelliJ. It is obviously not handled by Mocha itself. This structure has internal loops:
 * this.intellij_test_node.parent.children[0] === this.intellij_test_node
 *
 * This means the bug is in IntelliJ
 */

/* But then, why does npm test fails too?
 * [mocha this]
 *
 *   1) works when a precondition violation occurs when a function is called with a mocha fixture as this
 *
 *      >>> logs: Error: TypeError: Converting circular structure to JSON
 *      >>> logs:     at JSON.stringify (<anonymous>)
 *      >>> logs:     at makeSimple (node_modules/format-error/index.js:36:28)
 *      >>> logs:     at format (node_modules/format-error/index.js:39:21)
 *      >>> logs:     at Runner.<anonymous> (node_modules/mocha-reporter/index.js:283:18)
 *
 * This is an error in mocha-reporter!
 *
 * But without mocha-reporter, it is even weirder:

(node:18037) UnhandledPromiseRejectionWarning: Error: This condition intentionally fails.
    at Object.<anonymous> (/Users/jand/Scratchpad/toryt/contracts/test/_cases.js:51:26)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/jand/Scratchpad/toryt/contracts/test/99.mochaBugTest.js:22:15)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at /Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/mocha.js:330:36
    at Array.forEach (<anonymous>)
    at Mocha.loadFiles (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/mocha.js:327:14)
    at Mocha.run (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/mocha.js:804:10)
    at Object.exports.singleRun (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/cli/run-helpers.js:207:16)
    at exports.runMocha (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/cli/run-helpers.js:300:13)
    at Object.exports.handler.argv [as handler] (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/cli/run.js:296:3)
    at Object.runCommand (/Users/jand/Scratchpad/toryt/contracts/node_modules/yargs/lib/command.js:242:26)
    at Object.parseArgs [as _parseArgs] (/Users/jand/Scratchpad/toryt/contracts/node_modules/yargs/yargs.js:1087:28)
    at Object.parse (/Users/jand/Scratchpad/toryt/contracts/node_modules/yargs/yargs.js:566:25)
    at Object.exports.main (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/cli/cli.js:63:6)
    at Object.<anonymous> (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/bin/_mocha:10:23)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Function.Module.runMain (module.js:694:10)
    at startup (bootstrap_node.js:204:16)
    at bootstrap_node.js:625:3
(node:18037) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:18037) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
  mocha this
    1) works when a precondition violation occurs when a function is called with a mocha fixture as this
    *
 * Why is there an 'UnhandledPromiseRejectionWarning:'? There is nothing async here?!?!
 *
 * That was a false positive! Node detects our intentionallyRejectedPromise cases as a dangling rejection! Just by
 * being there.
 *
 * Mocha is ok
 * mocha-reporter has a bug
 *
 * So, these are 2 separate issues, one in IntelliJ, and one in mocha reporter, both falling back to JSON.stringify
 * problems with circular data structures. For intellij, in there own code. For mocha reporter, in the error that is
 * represented, deep down in node_modules/format-error/index.js, line 36, `makeSimple`.
 *
 * The format-error problem is known, and will not be fixed (2014!):
 * https://github.com/EndangeredMassa/format-error/issues/2
 *
 * Created an issue:
 * https://github.com/Wizcorp/mocha-reporter/issues/5
 *
 * The JetBrains issue seems not known.
 * Created an issue:
 * https://youtrack.jetbrains.com/issue/WEB-39186
 */
<commit_msg>only run the test in question on IntelliJ, on Node < 12<commit_after>/*
 Copyright 2019 - 2020 by Jan Dockx

 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.
 */

/* eslint-env mocha */

'use strict'

const Contract = require('../lib/IV/Contract')
const cases = require('./_cases')
const testUtil = require('./_util/testUtil')

const contract = new Contract({ pre: [cases.intentionallyFailingFunction] })

function isIntelliJOnNodeGT12 (fixture) {
  // noinspection JSUnresolvedVariable
  if (!fixture.test.intellij_test_node) {
    return false
  }
  // we are in IntelliJ, so surely in Node
  const versionString = process.version // syntax: 'vNN.MM.PP'
  const pattern = /^v(\d+)\.(\d+)\.(\d+)$/
  const majorVersionString = pattern.exec(versionString)[1]
  const majorVersion = Number.parseInt(majorVersionString)
  testUtil.log(`Major version of Node is ${majorVersion}`)
  // noinspection MagicNumberJS
  return majorVersion < 12
}

describe('mocha this', function () {
  before(function () {
    this.subject = contract.implementation(function () {})
  })

  it('works when a precondition violation occurs when a function is called with a mocha fixture as this', function () {
    if (isIntelliJOnNodeGT12(this)) {
      /* NOTE: This tests the workaround for a bug, that only occurs when running tests in IntelliJ, because of an
               unhandled circular structure in `this.test.intellij_test_node`. Eventually, Node util.inspect
               is called, and that cannot handle circular object structure in Node < 12. This test this is only
               sensible when in the context where the bug might occur. util.inspect was made more robust in Node 12,
               and now can deal with circular structures, so the bug does not appear in Node 12 or later.
               Since we still support Node 8 and 10, we need to keep this test until that has passed. */
      console.log(
        'executing a test that verifies the workaround to a bug that only occurs in IntelliJ or with mocha-reporter on Node < 12'
      )
      try {
        this.subject()
        true.should.be.false()
      } catch (err) {
        // logging the error produces the same problem, because console.log uses util.inspect too
        testUtil.log('' + err)
        const details = err.getDetails()
        testUtil.log(details)
        details.should.match(/𝕋⚖ \[\[failed to represent the value]]/)
        details.should.match(/\(Converting circular structure to JSON\)/)
        testUtil.log()
      }
    } else {
      console.log(
        'skipping a test that verifies the workaround to a bug that only occurs in IntelliJ or with mocha-reporter on Node < 12'
      )
    }
  })
})

/* Mocha Context has ctx.customInspect = true
 * The problem is in
 * node_modules/mocha/lib/runnable.js, line 231:
 *
 * /**
 *  * Inspect the runnable void of private properties.
 *  *
 *  * @private
 *  * @return {string}
 *  *-
 *  Runnable.prototype.inspect = function() {
 *    return JSON.stringify(
 *      this,
 *      function(key, val) {
 *        if (key[0] === '_') {
 *          return;
 *        }
 *        if (key === 'parent') {
 *          return '#<Suite>';
 *        }
 *        if (key === 'ctx') {
 *          return '#<Context>';
 *        }
 *        return val;
 *      },
 *      2
 *    );
 *  };
 *
 * `this ` still contains circular structures, apart from what the replacer handles.
 * this.ctx.test === this, but that should be handled by the replacer
 * this.parent.ctx.test === this, but that should be handled by the replacer
 *
 * There seems to be nothing else that can make this happen, except for `this.intellij_test_node`. This seems to be
 * added on by IntelliJ. It is obviously not handled by Mocha itself. This structure has internal loops:
 * this.intellij_test_node.parent.children[0] === this.intellij_test_node
 *
 * This means the bug is in IntelliJ
 */

/* But then, why does npm test fails too?
 * [mocha this]
 *
 *   1) works when a precondition violation occurs when a function is called with a mocha fixture as this
 *
 *      >>> logs: Error: TypeError: Converting circular structure to JSON
 *      >>> logs:     at JSON.stringify (<anonymous>)
 *      >>> logs:     at makeSimple (node_modules/format-error/index.js:36:28)
 *      >>> logs:     at format (node_modules/format-error/index.js:39:21)
 *      >>> logs:     at Runner.<anonymous> (node_modules/mocha-reporter/index.js:283:18)
 *
 * This is an error in mocha-reporter!
 *
 * But without mocha-reporter, it is even weirder:

(node:18037) UnhandledPromiseRejectionWarning: Error: This condition intentionally fails.
    at Object.<anonymous> (/Users/jand/Scratchpad/toryt/contracts/test/_cases.js:51:26)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/jand/Scratchpad/toryt/contracts/test/99.mochaBugTest.js:22:15)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at /Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/mocha.js:330:36
    at Array.forEach (<anonymous>)
    at Mocha.loadFiles (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/mocha.js:327:14)
    at Mocha.run (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/mocha.js:804:10)
    at Object.exports.singleRun (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/cli/run-helpers.js:207:16)
    at exports.runMocha (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/cli/run-helpers.js:300:13)
    at Object.exports.handler.argv [as handler] (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/cli/run.js:296:3)
    at Object.runCommand (/Users/jand/Scratchpad/toryt/contracts/node_modules/yargs/lib/command.js:242:26)
    at Object.parseArgs [as _parseArgs] (/Users/jand/Scratchpad/toryt/contracts/node_modules/yargs/yargs.js:1087:28)
    at Object.parse (/Users/jand/Scratchpad/toryt/contracts/node_modules/yargs/yargs.js:566:25)
    at Object.exports.main (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/lib/cli/cli.js:63:6)
    at Object.<anonymous> (/Users/jand/Scratchpad/toryt/contracts/node_modules/mocha/bin/_mocha:10:23)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Function.Module.runMain (module.js:694:10)
    at startup (bootstrap_node.js:204:16)
    at bootstrap_node.js:625:3
(node:18037) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:18037) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
  mocha this
    1) works when a precondition violation occurs when a function is called with a mocha fixture as this
    *
 * Why is there an 'UnhandledPromiseRejectionWarning:'? There is nothing async here?!?!
 *
 * That was a false positive! Node detects our intentionallyRejectedPromise cases as a dangling rejection! Just by
 * being there.
 *
 * Mocha is ok
 * mocha-reporter has a bug
 *
 * So, these are 2 separate issues, one in IntelliJ, and one in mocha reporter, both falling back to JSON.stringify
 * problems with circular data structures. For intellij, in there own code. For mocha reporter, in the error that is
 * represented, deep down in node_modules/format-error/index.js, line 36, `makeSimple`.
 *
 * The format-error problem is known, and will not be fixed (2014!):
 * https://github.com/EndangeredMassa/format-error/issues/2
 *
 * Created an issue:
 * https://github.com/Wizcorp/mocha-reporter/issues/5
 *
 * The JetBrains issue seems not known.
 * Created an issue:
 * https://youtrack.jetbrains.com/issue/WEB-39186
 */
<|endoftext|>


<commit_before>var url = require('url')
  , libxml = require('libxmljs')
  , https = require('https');

/**
 * Exposes FreshBooks HTTP Client.
 *
 * @param {String} url
 * @param {String} token
 * @api public
 */

var FreshBooks = module.exports = function(url, token) {
  if (!(this instanceof arguments.callee))
    throw new Error("FRESHBOOKS MUST BE CALLED WITH NEW KEYWORD");

  this.url = url;
  this.token = token;
  this.ns = "http://www.freshbooks.com/api/";

  this.Category = require('./Category');
  this.Category.prototype.freshbooks = this;

  this.Client = require('./Client');
  this.Client.prototype.freshbooks = this;

  this.Estimate = require('./Estimate');
  this.Estimate.prototype.freshbooks = this;

  this.Expense = require('./Expense');
  this.Expense.prototype.freshbooks = this;

  this.Gateway = require('./Gateway');
  this.Gateway.prototype.freshbooks = this;

  this.Invoice = require('./Invoice');
  this.Invoice.prototype.freshbooks = this;

  this.Item = require('./Item');
  this.Item.prototype.freshbooks = this;

  this.Language = require('./Language');
  this.Language.prototype.freshbooks = this;

  this.Payment = require('./Payment');
  this.Payment.prototype.freshbooks = this;

  this.Project = require('./Project');
  this.Project.prototype.freshbooks = this;

  this.Recurring = require('./Recurring');
  this.Recurring.prototype.freshbooks = this;

  this.Staff = require('./Staff');
  this.Staff.prototype.freshbooks = this;

  this.Task = require('./Task');
  this.Task.prototype.freshbooks = this;

  this.Tax = require('./Tax');
  this.Tax.prototype.freshbooks = this;

  this.Time_Entry = require('./Time_Entry');
  this.Time_Entry.prototype.freshbooks = this;
};

/**
 * Retrieves XML response from Freshbooks API.
 *
 * @param {Document} xml
 * @param {Function} fn
 * @api private
 */

FreshBooks.prototype._get = function(xml, fn) {
  var string = xml.toString();

  var options = {
      host: url.parse(this.url).hostname
    , port: url.parse(this.url).port
    , path: url.parse(this.url).path
    , method: 'POST'
    , headers: {
      'Content-Length': string.length
      , 'Authorization': 'Basic ' + new Buffer(this.token + ':X').toString('base64')
    }
  };

  var req = https.request(options, function(res) {
    string = '';
    res.setEncoding('utf8');

    res.on('data', function(chunk) {
      string += chunk;
    });

    res.on('end', function() {
      var err = null;
      try { xml = libxml.parseXmlString(string); }
      catch(e) { err = e; }

      fn(err, xml);
    });
  });

  req.on('error', function(err) {
    fn(new Error("CANNOT CONNECT TO FRESHBOOKS:" + err));
  });

  req.write(string);
  req.end();
};<commit_msg>Fix xml not formatted correctly<commit_after>var url = require('url')
  , libxml = require('libxmljs')
  , https = require('https');

/**
 * Exposes FreshBooks HTTP Client.
 *
 * @param {String} url
 * @param {String} token
 * @api public
 */

var FreshBooks = module.exports = function(url, token) {
  if (!(this instanceof arguments.callee))
    throw new Error("FRESHBOOKS MUST BE CALLED WITH NEW KEYWORD");

  this.url = url;
  this.token = token;
  this.ns = "http://www.freshbooks.com/api/";

  this.Category = require('./Category');
  this.Category.prototype.freshbooks = this;

  this.Client = require('./Client');
  this.Client.prototype.freshbooks = this;

  this.Estimate = require('./Estimate');
  this.Estimate.prototype.freshbooks = this;

  this.Expense = require('./Expense');
  this.Expense.prototype.freshbooks = this;

  this.Gateway = require('./Gateway');
  this.Gateway.prototype.freshbooks = this;

  this.Invoice = require('./Invoice');
  this.Invoice.prototype.freshbooks = this;

  this.Item = require('./Item');
  this.Item.prototype.freshbooks = this;

  this.Language = require('./Language');
  this.Language.prototype.freshbooks = this;

  this.Payment = require('./Payment');
  this.Payment.prototype.freshbooks = this;

  this.Project = require('./Project');
  this.Project.prototype.freshbooks = this;

  this.Recurring = require('./Recurring');
  this.Recurring.prototype.freshbooks = this;

  this.Staff = require('./Staff');
  this.Staff.prototype.freshbooks = this;

  this.Task = require('./Task');
  this.Task.prototype.freshbooks = this;

  this.Tax = require('./Tax');
  this.Tax.prototype.freshbooks = this;

  this.Time_Entry = require('./Time_Entry');
  this.Time_Entry.prototype.freshbooks = this;
};

/**
 * Retrieves XML response from Freshbooks API.
 *
 * @param {Document} xml
 * @param {Function} fn
 * @api private
 */

FreshBooks.prototype._get = function(xml, fn) {
  var string = xml.toString();

  var options = {
      host: url.parse(this.url).hostname
    , port: url.parse(this.url).port
    , path: url.parse(this.url).path
    , method: 'POST'
    , headers: {
      'Content-Length': Buffer.byteLength(string, 'utf8')
      , 'Authorization': 'Basic ' + new Buffer(this.token + ':X').toString('base64')
    }
  };

  var req = https.request(options, function(res) {
    string = '';
    res.setEncoding('utf8');

    res.on('data', function(chunk) {
      string += chunk;
    });

    res.on('end', function() {
      var err = null;
      try { xml = libxml.parseXmlString(string); }
      catch(e) { err = e; }

      fn(err, xml);
    });
  });

  req.on('error', function(err) {
    fn(new Error("CANNOT CONNECT TO FRESHBOOKS:" + err));
  });

  req.write(string);
  req.end();
};
<|endoftext|>