<commit_before>/**
 * @module ol/format/Feature
 */
import Geometry from '../geom/Geometry.js';
import {assign} from '../obj.js';
import {get as getProjection, equivalent as equivalentProjection, transformExtent} from '../proj.js';

/**
 * @typedef {Object} ReadOptions
 * @property {module:ol/proj~ProjectionLike} dataProjection Projection of the data we are reading.
 * If not provided, the projection will be derived from the data (where possible) or
 * the `dataProjection` of the format is assigned (where set). If the projection
 * can not be derived from the data and if no `dataProjection` is set for a format,
 * the features will not be reprojected.
 * @property {module:ol/extent~Extent} extent Tile extent of the tile being read. This is only used and
 * required for {@link module:ol/format/MVT}.
 * @property {module:ol/proj~ProjectionLike} featureProjection Projection of the feature geometries
 * created by the format reader. If not provided, features will be returned in the
 * `dataProjection`.
 */

/**
 * @typedef {Object} WriteOptions
 * @property {module:ol/proj~ProjectionLike} dataProjection Projection of the data we are writing.
 * If not provided, the `dataProjection` of the format is assigned (where set).
 * If no `dataProjection` is set for a format, the features will be returned
 * in the `featureProjection`.
 * @property {module:ol/proj~ProjectionLike} featureProjection Projection of the feature geometries
 * that will be serialized by the format writer. If not provided, geometries are assumed
 * to be in the `dataProjection` if that is set; in other words, they are not transformed.
 * @property {boolean} [rightHanded] When writing geometries, follow the right-hand
 * rule for linear ring orientation.  This means that polygons will have counter-clockwise
 * exterior rings and clockwise interior rings.  By default, coordinates are serialized
 * as they are provided at construction.  If `true`, the right-hand rule will
 * be applied.  If `false`, the left-hand rule will be applied (clockwise for
 * exterior and counter-clockwise for interior rings).  Note that not all
 * formats support this.  The GeoJSON format does use this property when writing
 * geometries.
 * @property {number} [decimals] Maximum number of decimal places for coordinates.
 * Coordinates are stored internally as floats, but floating-point arithmetic can create
 * coordinates with a large number of decimal places, not generally wanted on output.
 * Set a number here to round coordinates. Can also be used to ensure that
 * coordinates read in can be written back out with the same number of decimals.
 * Default is no rounding.
 */

/**
 * @classdesc
 * Abstract base class; normally only used for creating subclasses and not
 * instantiated in apps.
 * Base class for feature formats.
 * {module:ol/format/Feature~FeatureFormat} subclasses provide the ability to decode and encode
 * {@link module:ol/Feature~Feature} objects from a variety of commonly used geospatial
 * file formats.  See the documentation for each format for more details.
 *
 * @abstract
 * @api
 */
class FeatureFormat {
  constructor() {

    /**
     * @protected
     * @type {module:ol/proj/Projection}
     */
    this.dataProjection = null;

    /**
     * @protected
     * @type {module:ol/proj/Projection}
     */
    this.defaultFeatureProjection = null;

  }

  /**
   * Adds the data projection to the read options.
   * @param {Document|Node|Object|string} source Source.
   * @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
   * @return {module:ol/format/Feature~ReadOptions|undefined} Options.
   * @protected
   */
  getReadOptions(source, opt_options) {
    let options;
    if (opt_options) {
      options = {
        dataProjection: opt_options.dataProjection ?
          opt_options.dataProjection : this.readProjection(source),
        featureProjection: opt_options.featureProjection
      };
    }
    return this.adaptOptions(options);
  }

  /**
   * Sets the `dataProjection` on the options, if no `dataProjection`
   * is set.
   * @param {module:ol/format/Feature~WriteOptions|module:ol/format/Feature~ReadOptions|undefined} options
   *     Options.
   * @protected
   * @return {module:ol/format/Feature~WriteOptions|module:ol/format/Feature~ReadOptions|undefined}
   *     Updated options.
   */
  adaptOptions(options) {
    return assign({
      dataProjection: this.dataProjection,
      featureProjection: this.defaultFeatureProjection
    }, options);
  }

  /**
   * Get the extent from the source of the last {@link readFeatures} call.
   * @return {module:ol/extent~Extent} Tile extent.
   */
  getLastExtent() {
    return null;
  }

  /**
   * @abstract
   * @return {module:ol/format/FormatType} Format.
   */
  getType() {}

  /**
   * Read a single feature from a source.
   *
   * @abstract
   * @param {Document|Node|Object|string} source Source.
   * @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
   * @return {module:ol/Feature} Feature.
   */
  readFeature(source, opt_options) {}

  /**
   * Read all features from a source.
   *
   * @abstract
   * @param {Document|Node|ArrayBuffer|Object|string} source Source.
   * @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
   * @return {Array.<module:ol/Feature>} Features.
   */
  readFeatures(source, opt_options) {}

  /**
   * Read a single geometry from a source.
   *
   * @abstract
   * @param {Document|Node|Object|string} source Source.
   * @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
   * @return {module:ol/geom/Geometry} Geometry.
   */
  readGeometry(source, opt_options) {}

  /**
   * Read the projection from a source.
   *
   * @abstract
   * @param {Document|Node|Object|string} source Source.
   * @return {module:ol/proj/Projection} Projection.
   */
  readProjection(source) {}

  /**
   * Encode a feature in this format.
   *
   * @abstract
   * @param {module:ol/Feature} feature Feature.
   * @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
   * @return {string} Result.
   */
  writeFeature(feature, opt_options) {}

  /**
   * Encode an array of features in this format.
   *
   * @abstract
   * @param {Array.<module:ol/Feature>} features Features.
   * @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
   * @return {string} Result.
   */
  writeFeatures(features, opt_options) {}

  /**
   * Write a single geometry in this format.
   *
   * @abstract
   * @param {module:ol/geom/Geometry} geometry Geometry.
   * @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
   * @return {string} Result.
   */
  writeGeometry(geometry, opt_options) {}
}

export default FeatureFormat;

/**
 * @param {module:ol/geom/Geometry|module:ol/extent~Extent} geometry Geometry.
 * @param {boolean} write Set to true for writing, false for reading.
 * @param {module:ol/format/Feature~WriteOptions=|module:ol/format/Feature~ReadOptions=} opt_options
 *     Options.
 * @return {module:ol/geom/Geometry|module:ol/extent~Extent} Transformed geometry.
 */
export function transformWithOptions(geometry, write, opt_options) {
  const featureProjection = opt_options ?
    getProjection(opt_options.featureProjection) : null;
  const dataProjection = opt_options ?
    getProjection(opt_options.dataProjection) : null;
  /**
   * @type {module:ol/geom/Geometry|module:ol/extent~Extent}
   */
  let transformed;
  if (featureProjection && dataProjection &&
      !equivalentProjection(featureProjection, dataProjection)) {
    if (geometry instanceof Geometry) {
      transformed = (write ? geometry.clone() : geometry).transform(
        write ? featureProjection : dataProjection,
        write ? dataProjection : featureProjection);
    } else {
      // FIXME this is necessary because GML treats extents
      // as geometries
      transformed = transformExtent(
        geometry,
        dataProjection,
        featureProjection);
    }
  } else {
    transformed = geometry;
  }
  if (write && opt_options && opt_options.decimals !== undefined) {
    const power = Math.pow(10, opt_options.decimals);
    // if decimals option on write, round each coordinate appropriately
    /**
     * @param {Array.<number>} coordinates Coordinates.
     * @return {Array.<number>} Transformed coordinates.
     */
    const transform = function(coordinates) {
      for (let i = 0, ii = coordinates.length; i < ii; ++i) {
        coordinates[i] = Math.round(coordinates[i] * power) / power;
      }
      return coordinates;
    };
    if (transformed === geometry) {
      transformed = transformed.clone();
    }
    transformed.applyTransform(transform);
  }
  return transformed;
}
<commit_msg>Use alternative JSDoc annotation for optional parameter which passes the tests.<commit_after>/**
 * @module ol/format/Feature
 */
import Geometry from '../geom/Geometry.js';
import {assign} from '../obj.js';
import {get as getProjection, equivalent as equivalentProjection, transformExtent} from '../proj.js';

/**
 * @typedef {Object} ReadOptions
 * @property {module:ol/proj~ProjectionLike} dataProjection Projection of the data we are reading.
 * If not provided, the projection will be derived from the data (where possible) or
 * the `dataProjection` of the format is assigned (where set). If the projection
 * can not be derived from the data and if no `dataProjection` is set for a format,
 * the features will not be reprojected.
 * @property {module:ol/extent~Extent} extent Tile extent of the tile being read. This is only used and
 * required for {@link module:ol/format/MVT}.
 * @property {module:ol/proj~ProjectionLike} featureProjection Projection of the feature geometries
 * created by the format reader. If not provided, features will be returned in the
 * `dataProjection`.
 */

/**
 * @typedef {Object} WriteOptions
 * @property {module:ol/proj~ProjectionLike} dataProjection Projection of the data we are writing.
 * If not provided, the `dataProjection` of the format is assigned (where set).
 * If no `dataProjection` is set for a format, the features will be returned
 * in the `featureProjection`.
 * @property {module:ol/proj~ProjectionLike} featureProjection Projection of the feature geometries
 * that will be serialized by the format writer. If not provided, geometries are assumed
 * to be in the `dataProjection` if that is set; in other words, they are not transformed.
 * @property {boolean} [rightHanded] When writing geometries, follow the right-hand
 * rule for linear ring orientation.  This means that polygons will have counter-clockwise
 * exterior rings and clockwise interior rings.  By default, coordinates are serialized
 * as they are provided at construction.  If `true`, the right-hand rule will
 * be applied.  If `false`, the left-hand rule will be applied (clockwise for
 * exterior and counter-clockwise for interior rings).  Note that not all
 * formats support this.  The GeoJSON format does use this property when writing
 * geometries.
 * @property {number} [decimals] Maximum number of decimal places for coordinates.
 * Coordinates are stored internally as floats, but floating-point arithmetic can create
 * coordinates with a large number of decimal places, not generally wanted on output.
 * Set a number here to round coordinates. Can also be used to ensure that
 * coordinates read in can be written back out with the same number of decimals.
 * Default is no rounding.
 */

/**
 * @classdesc
 * Abstract base class; normally only used for creating subclasses and not
 * instantiated in apps.
 * Base class for feature formats.
 * {module:ol/format/Feature~FeatureFormat} subclasses provide the ability to decode and encode
 * {@link module:ol/Feature~Feature} objects from a variety of commonly used geospatial
 * file formats.  See the documentation for each format for more details.
 *
 * @abstract
 * @api
 */
class FeatureFormat {
  constructor() {

    /**
     * @protected
     * @type {module:ol/proj/Projection}
     */
    this.dataProjection = null;

    /**
     * @protected
     * @type {module:ol/proj/Projection}
     */
    this.defaultFeatureProjection = null;

  }

  /**
   * Adds the data projection to the read options.
   * @param {Document|Node|Object|string} source Source.
   * @param {module:ol/format/Feature~ReadOptions=} opt_options Options.
   * @return {module:ol/format/Feature~ReadOptions|undefined} Options.
   * @protected
   */
  getReadOptions(source, opt_options) {
    let options;
    if (opt_options) {
      options = {
        dataProjection: opt_options.dataProjection ?
          opt_options.dataProjection : this.readProjection(source),
        featureProjection: opt_options.featureProjection
      };
    }
    return this.adaptOptions(options);
  }

  /**
   * Sets the `dataProjection` on the options, if no `dataProjection`
   * is set.
   * @param {module:ol/format/Feature~WriteOptions|module:ol/format/Feature~ReadOptions|undefined} options
   *     Options.
   * @protected
   * @return {module:ol/format/Feature~WriteOptions|module:ol/format/Feature~ReadOptions|undefined}
   *     Updated options.
   */
  adaptOptions(options) {
    return assign({
      dataProjection: this.dataProjection,
      featureProjection: this.defaultFeatureProjection
    }, options);
  }

  /**
   * Get the extent from the source of the last {@link readFeatures} call.
   * @return {module:ol/extent~Extent} Tile extent.
   */
  getLastExtent() {
    return null;
  }

  /**
   * @abstract
   * @return {module:ol/format/FormatType} Format.
   */
  getType() {}

  /**
   * Read a single feature from a source.
   *
   * @abstract
   * @param {Document|Node|Object|string} source Source.
   * @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
   * @return {module:ol/Feature} Feature.
   */
  readFeature(source, opt_options) {}

  /**
   * Read all features from a source.
   *
   * @abstract
   * @param {Document|Node|ArrayBuffer|Object|string} source Source.
   * @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
   * @return {Array.<module:ol/Feature>} Features.
   */
  readFeatures(source, opt_options) {}

  /**
   * Read a single geometry from a source.
   *
   * @abstract
   * @param {Document|Node|Object|string} source Source.
   * @param {module:ol/format/Feature~ReadOptions=} opt_options Read options.
   * @return {module:ol/geom/Geometry} Geometry.
   */
  readGeometry(source, opt_options) {}

  /**
   * Read the projection from a source.
   *
   * @abstract
   * @param {Document|Node|Object|string} source Source.
   * @return {module:ol/proj/Projection} Projection.
   */
  readProjection(source) {}

  /**
   * Encode a feature in this format.
   *
   * @abstract
   * @param {module:ol/Feature} feature Feature.
   * @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
   * @return {string} Result.
   */
  writeFeature(feature, opt_options) {}

  /**
   * Encode an array of features in this format.
   *
   * @abstract
   * @param {Array.<module:ol/Feature>} features Features.
   * @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
   * @return {string} Result.
   */
  writeFeatures(features, opt_options) {}

  /**
   * Write a single geometry in this format.
   *
   * @abstract
   * @param {module:ol/geom/Geometry} geometry Geometry.
   * @param {module:ol/format/Feature~WriteOptions=} opt_options Write options.
   * @return {string} Result.
   */
  writeGeometry(geometry, opt_options) {}
}

export default FeatureFormat;

/**
 * @param {module:ol/geom/Geometry|module:ol/extent~Extent} geometry Geometry.
 * @param {boolean} write Set to true for writing, false for reading.
 * @param {module:ol/format/Feature~WriteOptions|module:ol/format/Feature~ReadOptions|undefined} opt_options
 *     Options.
 * @return {module:ol/geom/Geometry|module:ol/extent~Extent} Transformed geometry.
 */
export function transformWithOptions(geometry, write, opt_options) {
  const featureProjection = opt_options ?
    getProjection(opt_options.featureProjection) : null;
  const dataProjection = opt_options ?
    getProjection(opt_options.dataProjection) : null;
  /**
   * @type {module:ol/geom/Geometry|module:ol/extent~Extent}
   */
  let transformed;
  if (featureProjection && dataProjection &&
      !equivalentProjection(featureProjection, dataProjection)) {
    if (geometry instanceof Geometry) {
      transformed = (write ? geometry.clone() : geometry).transform(
        write ? featureProjection : dataProjection,
        write ? dataProjection : featureProjection);
    } else {
      // FIXME this is necessary because GML treats extents
      // as geometries
      transformed = transformExtent(
        geometry,
        dataProjection,
        featureProjection);
    }
  } else {
    transformed = geometry;
  }
  if (write && opt_options && opt_options.decimals !== undefined) {
    const power = Math.pow(10, opt_options.decimals);
    // if decimals option on write, round each coordinate appropriately
    /**
     * @param {Array.<number>} coordinates Coordinates.
     * @return {Array.<number>} Transformed coordinates.
     */
    const transform = function(coordinates) {
      for (let i = 0, ii = coordinates.length; i < ii; ++i) {
        coordinates[i] = Math.round(coordinates[i] * power) / power;
      }
      return coordinates;
    };
    if (transformed === geometry) {
      transformed = transformed.clone();
    }
    transformed.applyTransform(transform);
  }
  return transformed;
}
<|endoftext|>


<commit_before>var vscode = require('vscode');
var config = require('./config');
var constants = config.getConstants();
var azure = require('./azure');
var path = require('path');
var fs = require('fs');
var fsPath = require('fs-path');

// perform the export template feature
exports.exportTemplate = function exportTemplate(state) {
    this.getResourceGroups(state)
        .then(function () {
            vscode.window.showQuickPick(state.resourceGroupList)
                .then(function (selectedRg) {
                    if (!selectedRg) reject();
                    state.resourceGroupToUse = selectedRg;
                    azure.exportTemplate(state)
                        .then((result) => {
                            console.log(result);
                            var json = JSON.stringify(result.template);
                            var filename = path.join(vscode.workspace.rootPath, constants.armTemplatesPath, state.resourceGroupToUse, 'azuredeploy.json');
                            fsPath.writeFile(filename, json, (err) => {
                                if (result.error) {
                                    vscode.window.showErrorMessage(constants.promptTemplateExportedWithErrors.replace('{0}', state.resourceGroupToUse));
                                }
                                else {
                                    vscode.window.showInformationMessage(constants.promptTemplateExported.replace('{0}', state.resourceGroupToUse));
                                }
                                vscode.workspace.openTextDocument(filename)
                                .then(prms => {
                                    vscode.window.showTextDocument(prms);
                                    resolve();
                                });
                            });
                        });
                });
        })
        .catch(function (err) {
            vscode.window.showErrorMessage(err);
        });
};

// check to see if the user is logged in
exports.isLoggedIn = function isLoggedIn(state) {
    return new Promise((resolve, reject) => {
        if (state && state.credentials && state.accessToken && (state.subscriptions && state.subscriptions.length > 0)) {
            resolve();
        }
        else {
            vscode.window.showErrorMessage(constants.promptNotLoggedIn);
        }
    });
};

// deploys arm template
exports.deployTemplate = function deployTemplate(state) {
    state.statusBar = vscode.window.setStatusBarMessage(constants.promptDeployingTemplate
        .replace('{0}', state.selectedTemplateName)
        .replace('{1}', state.resourceGroupToUse))

    azure.deployTemplate(state)
        .then((msg) => {
            vscode.window.showInformationMessage(msg);
            state.statusBar.dispose();
        })
        .catch((err) => {
            vscode.window.showErrorMessage(constants.promptDeployingTemplateFailed
                .replace('{0}', state.selectedTemplateName)
                .replace('{1}', state.resourceGroupToUse));
            state.statusBar.dispose();
        });
};

// get the list of resource groups from the subscription
exports.getResourceGroups = function getResourceGroups(state) {
    return new Promise(function (resolve, reject) {
        azure
            .getResourceGroups(state)
            .then(function (result) {
                result.forEach(function (rg) {
                    state.resourceGroupList.push(rg.name);
                });
                resolve();
            })
            .catch(function (err) {
                reject(err);
            });
    });
};

// wrapper method for handling "new or existing resource group" workflows
exports.showNewOrExistingResourceGroupMenu = function showNewOrExistingResourceGroupMenu(state) {
    return new Promise((resolve, reject) => {
        vscode.window.showQuickPick([
            constants.optionExistingRg,
            constants.optionNewRg
        ]).then(selected => {
            if (selected == constants.optionExistingRg) {
                this.getResourceGroups(state)
                    .then(function () {
                        vscode.window.showQuickPick(state.resourceGroupList)
                            .then(function (selectedRg) {
                                if (!selectedRg) reject();
                                state.resourceGroupToUse = selectedRg;
                                resolve();
                            });
                    })
                    .catch(function (err) {
                        vscode.window.showErrorMessage(err);
                    });
            }
            else if (selected == constants.optionNewRg) {
                vscode.window.showInputBox({
                    prompt: constants.promptNewRgName
                }).then(function (newResourceGroupName) {
                    if (!newResourceGroupName || newResourceGroupName === "") reject();
                    state.resourceGroupToUse = newResourceGroupName;
                    azure.createNewResourceGroup(state).then(() => {
                        resolve();
                    });
                });
            }
        });
    });
};

// check the site's name
exports.ifWebSiteNameIsAvailable = function ifWebSiteNameIsAvailable(state) {
    return new Promise(function (resolve, reject) {
        azure
            .checkSiteNameAvailability(state)
            .then(function (result) {
                if (!result.nameAvailable) {
                    // name isn't available so we bail out'
                    reject(constants.promptWebSiteNameNotAvailable);
                }
                else {
                    resolve();
                }
            });
    });
};

// check the storage account's name
exports.ifStorageAccountNameIsAvailable = function ifStorageAccountNameIsAvailable(state) {
    return new Promise(function (resolve, reject) {
        azure
            .checkStorageAccountNameAvailability(state)
            .then(function (result) {
                if (!result.nameAvailable) {
                    // name isn't available so we bail out'
                    reject(constants.promptStorageAccountNameNotAvailable);
                }
                else {
                    resolve();
                }
            });
    });
};

// check the key vault name is available
exports.ifKeyVaultNameIsAvailable = function ifKeyVaultNameIsAvailable(state) {
    return new Promise(function (resolve, reject) {
        azure
            .checkKeyVaultNameAvailability(state)
            .then(function (result) {
                if (!result) {
                    // name isn't available so we bail out'
                    reject(constants.promptKeyVaultNameNotAvailable);
                }
                else {
                    resolve();
                }
            });
    });
}

// gets all of the resources
exports.getAzureResources = function getAzureResources(state) {
    return new Promise((function (resolve, reject) {
        var statusBar = vscode.window.setStatusBarMessage(constants.statusGettingResources);

        azure
            .getFullResourceList(state)
            .then(function (names) {
                statusBar.dispose();
                resolve(names);
            })
            .catch(function (err) {
                reject(err);
            });
    }));
};

// creates a new key vault
exports.createKeyVault = function createKeyVault(state, callback) {
    vscode.window.setStatusBarMessage(constants.statusCreatingKeyVault.replace('{0}', state.keyVaultName));
    azure
        .createNewKeyVault(state)
        .then(function (result) {
            vscode.window.setStatusBarMessage(constants.statusCreatedKeyVault.replace('{0}', state.keyVaultName));
            if (callback != null)
                callback();
        })
        .catch(function (err) {
            vscode.window.showErrorMessage(err);
        });
}

// method to create the resource group
exports.createResourceGroup = function createResourceGroup(state, callback) {
    vscode.window.setStatusBarMessage(constants.statusCreatingResourceGroup.replace('{0}', state.resourceGroupToUse));

    azure
        .createNewResourceGroup(state)
        .then(function (result) {
            vscode.window.setStatusBarMessage(constants.statusCreatedResourceGroup.replace('{0}', state.resourceGroupToUse));
            if (callback != null)
                callback();
        })
        .catch(function (err) {
            vscode.window.showErrorMessage(err);
        });
}

// create the server farm
exports.createServerFarm = function createServerFarm(state, callback) {
    vscode.window.setStatusBarMessage(constants.statusCreatingServerFarm.replace('{0}', state.selectedServerFarm));

    azure
        .createNewServerFarm(state)
        .then(function (result) {
            vscode.window.setStatusBarMessage(constants.statusCreatedResourceGroup.replace('{0}', state.selectedServerFarm));
            if (callback != null)
                callback();
        })
        .catch(function (err) {
            vscode.window.showErrorMessage(err);
        });
}

// creates the web app based on the state persisted up to this point
exports.createWebApp = function createWebApp(state, callback) {
    vscode.window.setStatusBarMessage(constants.promptWebAppCreationInProcess.replace('{0}', state.newWebAppName));

    azure
        .createWebApp(state)
        .then(function (result) {
            console.log(result);
            vscode.window.setStatusBarMessage(constants.promptWebAppCreated.replace('{0}', state.newWebAppName));
            if (callback != null)
                callback();
        })
        .catch(function (err) {
            vscode.window.showErrorMessage(err);
        });
}

// creates the function app based on the state persisted up to this point
exports.createFunction = function createFunction(state, callback) {
    vscode.window.setStatusBarMessage(constants.promptFunctionAppCreationInProcess.replace('{0}', state.newWebAppName));

    azure
        .createFunction(state)
        .then(function (result) {
            console.log(result);
            vscode.window.setStatusBarMessage(constants.promptFunctionAppCreated.replace('{0}', state.newWebAppName));
            if (callback != null)
                callback();
        })
        .catch(function (err) {
            vscode.window.showErrorMessage(err);
        });
}

// gets all the hosting plans
exports.getServerFarms = function getServerFarms(state) {
    return new Promise(function (resolve, reject) {
        state.serverFarmList = [];
        var statusBar = vscode.window.setStatusBarMessage(constants.statusGettingFarms);
        azure
            .getServerFarms(state)
            .then(function (result) {
                statusBar.dispose();
                if (result.length == 0)
                    resolve();
                else {
                    result.forEach(function (farm, index, arr) {
                        state.serverFarmList.push(farm.name);
                        if (index == arr.length - 1) {
                            resolve();
                        }
                    });
                }
            })
            .catch(function (err) {
                reject(err);
            });
    });
}

// lists all storage accounts in subscription
exports.getStorageAccounts = function getStorageAccounts(state) {
    return new Promise(function (resolve, reject) {
        state.storageAccountList = [];
        azure
            .getStorageAccounts(state)
            .then(function (result) {
                if (result.length === 0)
                    vscode.window.showErrorMessage(constants.promptNoStorageAccount);
                else {
                    result.forEach((item, index, arr) => {
                        state.storageAccountList.push(item);
                        if (index === arr.length - 1)
                            resolve();
                    });
                }
            })
            .catch(function (err) {
                vscode.window.showErrorMessage(err);
            });
    });
}

// create new storage account
exports.createStorageAccount = function createStorageAccount(state, callback) {
    return new Promise((resolve, reject) => {
        vscode.window.setStatusBarMessage(constants.statusCreatingStorageAccount.replace('{0}', state.selectedStorageAccount));
        azure
            .createStorageAccount(state)
            .then((result) => {
                vscode.window.setStatusBarMessage(constants.statusCreatedStorageAccount.replace('{0}', state.selectedStorageAccount));
                if (callback !== null)
                    callback(result);
            })
            .catch(function (err) {
                vscode.window.showErrorMessage(err);
            });
    });
}

// list storage account keys
exports.getStorageAccountKeys = function getStorageAccountKeys(state) {

    return new Promise(function (resolve, reject) {
        azure
            .getStorageAccountKeys(state)
            .then(function (result) {
                if (result.keys.length == 0)
                    reject();
                else {
                    state.storageAccountKeyList = [];

                    if (result.keys.length != 0)
                        resolve();
                    else
                        reject();

                    result.keys.forEach(function (item, index, arr) {
                        state.storageAccountKeyList.push(item);
                    });
                }
            })
            .catch(function (err) {
                vscode.window.showErrorMessage(err);
                reject();
            });
    });
};

var buttons = [];

exports.showSubscriptionStatusBarButton = function showSubscriptionStatusBarButton() {
    showButton('selectsubscription', '$(cloud-upload)', 'Select the active Azure subscription');
};

exports.showSelectRegionStatusBarButton = function showSelectRegionStatusBarButton() {
    showButton('selectRegion', '$(globe)', 'Select your desired Azure region');
};

exports.getRegions = function getRegions(state) {
    return new Promise(function (resolve, reject) {
        azure
            .getRegions(state)
            .then(function (result) {
                state.regions = result;
                state.selectedRegion = state.regions[0].displayName;
                resolve();
            })
            .catch(function (err) {
                vscode.window.showErrorMessage(err);
            });
    });
};

exports.getRegionsForResource = function getRegionsForResource(state, resourceProvider, resourceType) {
    return new Promise(function (resolve, reject) {
        azure
            .getRegionsForResource(state, resourceProvider, resourceType)
            .then(function (result) {
                resolve(result);
            })
            .catch(function (err) {
                vscode.window.showErrorMessage(err);
            });
    });
}

exports.showResourceGroupsMenu = function showResourceGroupsMenu(state, callback) {
    var resourceGroupNames = state.resourceGroupList.map(function (x) { return x; });
    vscode.window.showQuickPick(resourceGroupNames).then(function (selected) {
        if (!selected) return;

        state.resourceGroupToUse = selected;
        vscode.window.setStatusBarMessage(constants.statusResourceGroupSelected.replace('{0}', state.resourceGroupToUse));

        if (callback !== null)
            callback();
    });
};

exports.showRegionMenu = function showRegionMenu(state) {
    var regionNames = state.regions.map(function (x) { return x.displayName; });
    vscode.window.showQuickPick(regionNames).then(function (selected) {
        if (!selected) return;

        state.selectedRegion = selected;
        vscode.window.setStatusBarMessage(constants.statusRegionSelected.replace('{0}', state.selectedRegion));
        updateButtonTooltip('selectRegion', constants.btnRegionSelectionLabel + '('
            + constants.statusRegionSelected.replace('{0}', state.selectedRegion) + ')');

    });
};

exports.showStorageAccountMenu = function showStorageMenu(state) {
    return new Promise(function (resolve, reject) {
        var storageAccountNames = state.storageAccountList.map(function (x) { return x.name; });
        vscode.window.showQuickPick(storageAccountNames).then(function (selected) {
            if (!selected)
                resolve(null);
            else {
                state.selectedStorageAccount = selected;
                vscode.window.setStatusBarMessage(constants.statusStorageAccountSelected.replace('{0}', state.selectedStorageAccount));
                updateButtonTooltip('selectStorageAccount', constants.btnStorageSelectionLabel + '('
                    + constants.statusStorageAccountSelected.replace('{0}', state.selectedStorageAccount) + ')');
                resolve(selected);
            }
        });
    });
};

function showButton(command, text, tooltip) {
    var customStatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 0);
    customStatusBarItem.color = 'white';
    customStatusBarItem.command = command;
    customStatusBarItem.text = text;
    customStatusBarItem.tooltip = tooltip;
    customStatusBarItem.show();
    buttons.push(customStatusBarItem);
};

function updateButtonTooltip(command, tooltip) {
    var x = buttons.filter(function (f) {
        return f.command == command;
    });
    if (x != null && x.length > 0)
        x[0].tooltip = tooltip;
};<commit_msg>minor tweak<commit_after>var vscode = require('vscode');
var config = require('./config');
var constants = config.getConstants();
var azure = require('./azure');
var path = require('path');
var fs = require('fs');
var fsPath = require('fs-path');

// perform the export template feature
exports.exportTemplate = function exportTemplate(state) {
    this.getResourceGroups(state)
        .then(function () {
            vscode.window.showQuickPick(state.resourceGroupList)
                .then(function (selectedRg) {
                    if (!selectedRg) reject();
                    state.resourceGroupToUse = selectedRg;
                    azure.exportTemplate(state)
                        .then((result) => {
                            console.log(result);
                            var json = JSON.stringify(result.template);
                            var filename = path.join(vscode.workspace.rootPath, constants.armTemplatesPath, state.resourceGroupToUse, 'azuredeploy.json');
                            fsPath.writeFile(filename, json, (err) => {
                                if (result.error) {
                                    vscode.window.showErrorMessage(constants.promptTemplateExportedWithErrors.replace('{0}', state.resourceGroupToUse));
                                }
                                else {
                                    vscode.window.showInformationMessage(constants.promptTemplateExported.replace('{0}', state.resourceGroupToUse));
                                }
                                vscode.workspace.openTextDocument(filename)
                                .then(prms => {
                                    vscode.window.showTextDocument(prms);
                                });
                            });
                        });
                });
        })
        .catch(function (err) {
            vscode.window.showErrorMessage(err);
        });
};

// check to see if the user is logged in
exports.isLoggedIn = function isLoggedIn(state) {
    return new Promise((resolve, reject) => {
        if (state && state.credentials && state.accessToken && (state.subscriptions && state.subscriptions.length > 0)) {
            resolve();
        }
        else {
            vscode.window.showErrorMessage(constants.promptNotLoggedIn);
        }
    });
};

// deploys arm template
exports.deployTemplate = function deployTemplate(state) {
    state.statusBar = vscode.window.setStatusBarMessage(constants.promptDeployingTemplate
        .replace('{0}', state.selectedTemplateName)
        .replace('{1}', state.resourceGroupToUse))

    azure.deployTemplate(state)
        .then((msg) => {
            vscode.window.showInformationMessage(msg);
            state.statusBar.dispose();
        })
        .catch((err) => {
            vscode.window.showErrorMessage(constants.promptDeployingTemplateFailed
                .replace('{0}', state.selectedTemplateName)
                .replace('{1}', state.resourceGroupToUse));
            state.statusBar.dispose();
        });
};

// get the list of resource groups from the subscription
exports.getResourceGroups = function getResourceGroups(state) {
    return new Promise(function (resolve, reject) {
        azure
            .getResourceGroups(state)
            .then(function (result) {
                result.forEach(function (rg) {
                    state.resourceGroupList.push(rg.name);
                });
                resolve();
            })
            .catch(function (err) {
                reject(err);
            });
    });
};

// wrapper method for handling "new or existing resource group" workflows
exports.showNewOrExistingResourceGroupMenu = function showNewOrExistingResourceGroupMenu(state) {
    return new Promise((resolve, reject) => {
        vscode.window.showQuickPick([
            constants.optionExistingRg,
            constants.optionNewRg
        ]).then(selected => {
            if (selected == constants.optionExistingRg) {
                this.getResourceGroups(state)
                    .then(function () {
                        vscode.window.showQuickPick(state.resourceGroupList)
                            .then(function (selectedRg) {
                                if (!selectedRg) reject();
                                state.resourceGroupToUse = selectedRg;
                                resolve();
                            });
                    })
                    .catch(function (err) {
                        vscode.window.showErrorMessage(err);
                    });
            }
            else if (selected == constants.optionNewRg) {
                vscode.window.showInputBox({
                    prompt: constants.promptNewRgName
                }).then(function (newResourceGroupName) {
                    if (!newResourceGroupName || newResourceGroupName === "") reject();
                    state.resourceGroupToUse = newResourceGroupName;
                    azure.createNewResourceGroup(state).then(() => {
                        resolve();
                    });
                });
            }
        });
    });
};

// check the site's name
exports.ifWebSiteNameIsAvailable = function ifWebSiteNameIsAvailable(state) {
    return new Promise(function (resolve, reject) {
        azure
            .checkSiteNameAvailability(state)
            .then(function (result) {
                if (!result.nameAvailable) {
                    // name isn't available so we bail out'
                    reject(constants.promptWebSiteNameNotAvailable);
                }
                else {
                    resolve();
                }
            });
    });
};

// check the storage account's name
exports.ifStorageAccountNameIsAvailable = function ifStorageAccountNameIsAvailable(state) {
    return new Promise(function (resolve, reject) {
        azure
            .checkStorageAccountNameAvailability(state)
            .then(function (result) {
                if (!result.nameAvailable) {
                    // name isn't available so we bail out'
                    reject(constants.promptStorageAccountNameNotAvailable);
                }
                else {
                    resolve();
                }
            });
    });
};

// check the key vault name is available
exports.ifKeyVaultNameIsAvailable = function ifKeyVaultNameIsAvailable(state) {
    return new Promise(function (resolve, reject) {
        azure
            .checkKeyVaultNameAvailability(state)
            .then(function (result) {
                if (!result) {
                    // name isn't available so we bail out'
                    reject(constants.promptKeyVaultNameNotAvailable);
                }
                else {
                    resolve();
                }
            });
    });
}

// gets all of the resources
exports.getAzureResources = function getAzureResources(state) {
    return new Promise((function (resolve, reject) {
        var statusBar = vscode.window.setStatusBarMessage(constants.statusGettingResources);

        azure
            .getFullResourceList(state)
            .then(function (names) {
                statusBar.dispose();
                resolve(names);
            })
            .catch(function (err) {
                reject(err);
            });
    }));
};

// creates a new key vault
exports.createKeyVault = function createKeyVault(state, callback) {
    vscode.window.setStatusBarMessage(constants.statusCreatingKeyVault.replace('{0}', state.keyVaultName));
    azure
        .createNewKeyVault(state)
        .then(function (result) {
            vscode.window.setStatusBarMessage(constants.statusCreatedKeyVault.replace('{0}', state.keyVaultName));
            if (callback != null)
                callback();
        })
        .catch(function (err) {
            vscode.window.showErrorMessage(err);
        });
}

// method to create the resource group
exports.createResourceGroup = function createResourceGroup(state, callback) {
    vscode.window.setStatusBarMessage(constants.statusCreatingResourceGroup.replace('{0}', state.resourceGroupToUse));

    azure
        .createNewResourceGroup(state)
        .then(function (result) {
            vscode.window.setStatusBarMessage(constants.statusCreatedResourceGroup.replace('{0}', state.resourceGroupToUse));
            if (callback != null)
                callback();
        })
        .catch(function (err) {
            vscode.window.showErrorMessage(err);
        });
}

// create the server farm
exports.createServerFarm = function createServerFarm(state, callback) {
    vscode.window.setStatusBarMessage(constants.statusCreatingServerFarm.replace('{0}', state.selectedServerFarm));

    azure
        .createNewServerFarm(state)
        .then(function (result) {
            vscode.window.setStatusBarMessage(constants.statusCreatedResourceGroup.replace('{0}', state.selectedServerFarm));
            if (callback != null)
                callback();
        })
        .catch(function (err) {
            vscode.window.showErrorMessage(err);
        });
}

// creates the web app based on the state persisted up to this point
exports.createWebApp = function createWebApp(state, callback) {
    vscode.window.setStatusBarMessage(constants.promptWebAppCreationInProcess.replace('{0}', state.newWebAppName));

    azure
        .createWebApp(state)
        .then(function (result) {
            console.log(result);
            vscode.window.setStatusBarMessage(constants.promptWebAppCreated.replace('{0}', state.newWebAppName));
            if (callback != null)
                callback();
        })
        .catch(function (err) {
            vscode.window.showErrorMessage(err);
        });
}

// creates the function app based on the state persisted up to this point
exports.createFunction = function createFunction(state, callback) {
    vscode.window.setStatusBarMessage(constants.promptFunctionAppCreationInProcess.replace('{0}', state.newWebAppName));

    azure
        .createFunction(state)
        .then(function (result) {
            console.log(result);
            vscode.window.setStatusBarMessage(constants.promptFunctionAppCreated.replace('{0}', state.newWebAppName));
            if (callback != null)
                callback();
        })
        .catch(function (err) {
            vscode.window.showErrorMessage(err);
        });
}

// gets all the hosting plans
exports.getServerFarms = function getServerFarms(state) {
    return new Promise(function (resolve, reject) {
        state.serverFarmList = [];
        var statusBar = vscode.window.setStatusBarMessage(constants.statusGettingFarms);
        azure
            .getServerFarms(state)
            .then(function (result) {
                statusBar.dispose();
                if (result.length == 0)
                    resolve();
                else {
                    result.forEach(function (farm, index, arr) {
                        state.serverFarmList.push(farm.name);
                        if (index == arr.length - 1) {
                            resolve();
                        }
                    });
                }
            })
            .catch(function (err) {
                reject(err);
            });
    });
}

// lists all storage accounts in subscription
exports.getStorageAccounts = function getStorageAccounts(state) {
    return new Promise(function (resolve, reject) {
        state.storageAccountList = [];
        azure
            .getStorageAccounts(state)
            .then(function (result) {
                if (result.length === 0)
                    vscode.window.showErrorMessage(constants.promptNoStorageAccount);
                else {
                    result.forEach((item, index, arr) => {
                        state.storageAccountList.push(item);
                        if (index === arr.length - 1)
                            resolve();
                    });
                }
            })
            .catch(function (err) {
                vscode.window.showErrorMessage(err);
            });
    });
}

// create new storage account
exports.createStorageAccount = function createStorageAccount(state, callback) {
    return new Promise((resolve, reject) => {
        vscode.window.setStatusBarMessage(constants.statusCreatingStorageAccount.replace('{0}', state.selectedStorageAccount));
        azure
            .createStorageAccount(state)
            .then((result) => {
                vscode.window.setStatusBarMessage(constants.statusCreatedStorageAccount.replace('{0}', state.selectedStorageAccount));
                if (callback !== null)
                    callback(result);
            })
            .catch(function (err) {
                vscode.window.showErrorMessage(err);
            });
    });
}

// list storage account keys
exports.getStorageAccountKeys = function getStorageAccountKeys(state) {

    return new Promise(function (resolve, reject) {
        azure
            .getStorageAccountKeys(state)
            .then(function (result) {
                if (result.keys.length == 0)
                    reject();
                else {
                    state.storageAccountKeyList = [];

                    if (result.keys.length != 0)
                        resolve();
                    else
                        reject();

                    result.keys.forEach(function (item, index, arr) {
                        state.storageAccountKeyList.push(item);
                    });
                }
            })
            .catch(function (err) {
                vscode.window.showErrorMessage(err);
                reject();
            });
    });
};

var buttons = [];

exports.showSubscriptionStatusBarButton = function showSubscriptionStatusBarButton() {
    showButton('selectsubscription', '$(cloud-upload)', 'Select the active Azure subscription');
};

exports.showSelectRegionStatusBarButton = function showSelectRegionStatusBarButton() {
    showButton('selectRegion', '$(globe)', 'Select your desired Azure region');
};

exports.getRegions = function getRegions(state) {
    return new Promise(function (resolve, reject) {
        azure
            .getRegions(state)
            .then(function (result) {
                state.regions = result;
                state.selectedRegion = state.regions[0].displayName;
                resolve();
            })
            .catch(function (err) {
                vscode.window.showErrorMessage(err);
            });
    });
};

exports.getRegionsForResource = function getRegionsForResource(state, resourceProvider, resourceType) {
    return new Promise(function (resolve, reject) {
        azure
            .getRegionsForResource(state, resourceProvider, resourceType)
            .then(function (result) {
                resolve(result);
            })
            .catch(function (err) {
                vscode.window.showErrorMessage(err);
            });
    });
}

exports.showResourceGroupsMenu = function showResourceGroupsMenu(state, callback) {
    var resourceGroupNames = state.resourceGroupList.map(function (x) { return x; });
    vscode.window.showQuickPick(resourceGroupNames).then(function (selected) {
        if (!selected) return;

        state.resourceGroupToUse = selected;
        vscode.window.setStatusBarMessage(constants.statusResourceGroupSelected.replace('{0}', state.resourceGroupToUse));

        if (callback !== null)
            callback();
    });
};

exports.showRegionMenu = function showRegionMenu(state) {
    var regionNames = state.regions.map(function (x) { return x.displayName; });
    vscode.window.showQuickPick(regionNames).then(function (selected) {
        if (!selected) return;

        state.selectedRegion = selected;
        vscode.window.setStatusBarMessage(constants.statusRegionSelected.replace('{0}', state.selectedRegion));
        updateButtonTooltip('selectRegion', constants.btnRegionSelectionLabel + '('
            + constants.statusRegionSelected.replace('{0}', state.selectedRegion) + ')');

    });
};

exports.showStorageAccountMenu = function showStorageMenu(state) {
    return new Promise(function (resolve, reject) {
        var storageAccountNames = state.storageAccountList.map(function (x) { return x.name; });
        vscode.window.showQuickPick(storageAccountNames).then(function (selected) {
            if (!selected)
                resolve(null);
            else {
                state.selectedStorageAccount = selected;
                vscode.window.setStatusBarMessage(constants.statusStorageAccountSelected.replace('{0}', state.selectedStorageAccount));
                updateButtonTooltip('selectStorageAccount', constants.btnStorageSelectionLabel + '('
                    + constants.statusStorageAccountSelected.replace('{0}', state.selectedStorageAccount) + ')');
                resolve(selected);
            }
        });
    });
};

function showButton(command, text, tooltip) {
    var customStatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 0);
    customStatusBarItem.color = 'white';
    customStatusBarItem.command = command;
    customStatusBarItem.text = text;
    customStatusBarItem.tooltip = tooltip;
    customStatusBarItem.show();
    buttons.push(customStatusBarItem);
};

function updateButtonTooltip(command, tooltip) {
    var x = buttons.filter(function (f) {
        return f.command == command;
    });
    if (x != null && x.length > 0)
        x[0].tooltip = tooltip;
};<|endoftext|>


<commit_before>(function() {
  var VM = function VM() {
    this.pc = 0x200;
    this.stack = new Array;
    this.stackPointer = 0;
    this.screen = { clear: function() {}, render: function() {}, setPixel: function() {} };
    this.input = { isKeyPressed: function(key) {} };
    this.v = new Uint8Array(16);
    this.i = 0;
    this.memory = new Uint8Array(4096);
    this.delayTimer = 0;
    this.soundTimer = 0;
    this.paused = false;
    this.speed = 10;

    var fonts = [
      0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
      0x20, 0x60, 0x20, 0x20, 0x70, // 1
      0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
      0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
      0x90, 0x90, 0xF0, 0x10, 0x10, // 4
      0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
      0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
      0xF0, 0x10, 0x20, 0x40, 0x40, // 7
      0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
      0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
      0xF0, 0x90, 0xF0, 0x90, 0x90, // A
      0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
      0xF0, 0x80, 0x80, 0x80, 0xF0, // C
      0xE0, 0x90, 0x90, 0x90, 0xE0, // D
      0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
      0xF0, 0x80, 0xF0, 0x80, 0x80  // F
    ];

    for (var i = 0, length = fonts.length; i < length; i++) {
      this.memory[i] = fonts[i];
    }

    this.loadProgram = function(program) {
      for (var i = 0, length = program.length; i < length; i++) {
        this.memory[0x200 + i] = program[i];
      }
    }

    this.cycle = function() {
      for (var i = 0; i < this.speed; i++) {
        if (!this.paused) {
          var opcode = this.memory[this.pc] << 8 | this.memory[this.pc + 1];
          this.perform(opcode);
          this.updateTimers();
        }
      }

      this.render();
    }

    this.perform = function(opcode) {
      this.pc += 2;

      var x = (opcode & 0x0F00) >> 8;
      var y = (opcode & 0x00F0) >> 4;

      switch (opcode & 0xF000) {
        case 0x000:
          switch(opcode) {
            case 0x00E0:
              this.screen.clear();
              break;

            case 0x00EE:
              this.stackPointer -= 1;
              this.pc = this.stack[this.stackPointer];
              break;
          }
          break;

        case 0xA000:
          this.i = opcode & 0x0FFF;
          break;

        case 0xB000:
          this.pc = (opcode & 0x0FFF) + this.v[0];
          break;

        case 0x1000:
          this.pc = opcode & 0x0FFF;
          break;

        case 0x2000:
          this.stack[this.stackPointer] = this.pc;
          this.stackPointer += 1;
          this.pc = opcode & 0x0FFF;
          break;

        case 0x3000:
          if (this.v[x] == (opcode & 0x00FF)) {
            this.pc += 2;
          }
          break;

        case 0x4000:
          if (this.v[x] != (opcode & 0x00FF)) {
            this.pc += 2;
          }
          break;

        case 0x5000:
          if (this.v[x] == this.v[y]) {
            this.pc += 2;
          }
          break;

        case 0x6000:
          this.v[x] = opcode & 0x00FF;
          break;

        case 0x7000:
          this.v[x] += opcode & 0x00FF;
          break;

        case 0x8000:
          switch (opcode & 0x000F) {
            case 0x0000:
              this.v[x] = this.v[y];
              break;

            case 0x0001:
              this.v[x] = this.v[x] | this.v[y];
              break;

            case 0x0002:
              this.v[x] = this.v[x] & this.v[y];
              break;

            case 0x0003:
              this.v[x] = this.v[x] ^ this.v[y];
              break;

            case 0x0004:
              var sum = this.v[x] + this.v[y];

              if (sum > 0xFF) {
                this.v[0xF] = 1;
              } else {
                this.v[0xF] = 0;
              }

              this.v[x] = sum;
              break;

            case 0x0005:
              if(this.v[x] > this.v[y]) {
                this.v[0xF] = 1;
              } else {
                this.v[0xF] = 0;
              }

              this.v[x] = this.v[x] - this.v[y];
              break;

            case 0x0006:
              this.v[0xF] = this.v[x] & 0x01;
              this.v[x] = this.v[x] >> 1;
              break;

            case 0x0007:
              if (this.v[x] > this.v[y]) {
                this.v[0xF] = 0;
              } else {
                this.v[0xF] = 1;
              }

              this.v[x] = this.v[y] - this.v[x];
              break;

            case 0x000E:
              this.v[0xF] = this.v[x] & 0x80;
              this.v[x] = this.v[x] << 1;
              break;
          }
          break;

        case 0x9000:
          if (this.v[x] != this.v[y]) this.pc += 2;
          break;

        case 0xC000:
          this.v[x] = Math.floor(Math.random() * 0xFF) & (opcode & 0x00FF);
          break;

        case 0xD000:
          var row, col, sprite
            , width = 8
            , height = opcode & 0x000F;

          this.v[0xF] = 0;

          for (row = 0; row < height; row++) {
            sprite = this.memory[this.i + row];

            for (col = 0; col < width; col++) {
              if ((sprite & 0x80) > 0) {
                if (this.screen.setPixel(this.v[x] + col, this.v[y] + row)) {
                  this.v[0xF] = 1;
                }
              }

              sprite = sprite << 1;
            }
          }

          break;

        case 0xE000:
          switch (opcode & 0x00FF) {
            case 0x009E:
              if (this.input.isKeyPressed(this.v[x])) {
                this.pc += 2;
              }
              break;

            case 0x00A1:
              if (!this.input.isKeyPressed(this.v[x])) {
                this.pc += 2;
              }
              break;
          }
          break;

        case 0xF000:
          switch (opcode & 0x00FF) {
            case 0x0007:
              this.v[x] = this.delayTimer;
              break;

            case 0x000A:
              this.paused = true;

              this.input.onKeyPress = function(key) {
                this.v[x] = key;
                this.paused = false;
                this.input.onKeyPress = function() {}
              }.bind(this);

            case 0x0015:
              this.delayTimer = this.v[x];
              break;

            case 0x0018:
              this.soundTimer = this.v[x];
              break;

            case 0x0029:
              this.i = this.v[x] * 5;
              break;

            case 0x0033:
              this.memory[this.i]     = parseInt(this.v[x] / 100);
              this.memory[this.i + 1] = parseInt(this.v[x] % 100 / 10);
              this.memory[this.i + 2] = this.v[x] % 10;
              break;

            case 0x0055:
              for (var i = 0; i <= x; i++) {
                this.memory[this.i + i] = this.v[i];
              }
              break;

            case 0x0065:
              for (var i = 0; i <= x; i++) {
                this.v[i] = this.memory[this.i + i];
              }
              break;

            case 0x001E:
              this.i += this.v[x];
              break;
          }

          break;

        default:
          throw new Error("Unknow opcode " + opcode.toString(16) + " informed.");
      }
    }

    this.render = function() {
      this.screen.render();
    }

    this.updateTimers = function() {
      if (this.delayTimer > 0) this.delayTimer -= 1;
      if (this.soundTimer > 0) this.soundTimer -= 1;
    }
  }

  module.exports = VM;
})();
<commit_msg>Adding a reset function.<commit_after>(function() {
  var VM = function VM() {
    this.pc = 0x200;
    this.stack = new Array;
    this.stackPointer = 0;
    this.screen = { clear: function() {}, render: function() {}, setPixel: function() {} };
    this.input = { isKeyPressed: function(key) {} };
    this.v = new Uint8Array(16);
    this.i = 0;
    this.memory = new Uint8Array(4096);
    this.delayTimer = 0;
    this.soundTimer = 0;
    this.paused = false;
    this.speed = 10;

    this.loadFonts = function() {
      var fonts = [
        0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
        0x20, 0x60, 0x20, 0x20, 0x70, // 1
        0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
        0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
        0x90, 0x90, 0xF0, 0x10, 0x10, // 4
        0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
        0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
        0xF0, 0x10, 0x20, 0x40, 0x40, // 7
        0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
        0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
        0xF0, 0x90, 0xF0, 0x90, 0x90, // A
        0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
        0xF0, 0x80, 0x80, 0x80, 0xF0, // C
        0xE0, 0x90, 0x90, 0x90, 0xE0, // D
        0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
        0xF0, 0x80, 0xF0, 0x80, 0x80  // F
      ];

      for (var i = 0, length = fonts.length; i < length; i++) {
        this.memory[i] = fonts[i];
      }
    }

    this.reset = function() {
      this.pc = 0x200;
      this.stack = new Array;
      this.stackPointer = 0;
      this.v = new Uint8Array(16);
      this.i = 0;
      this.memory = new Uint8Array(4096);
      this.delayTimer = 0;
      this.soundTimer = 0;
      this.screen.clear();
      this.input.clear();
      this.loadFonts();
      this.paused = false;
    }

    this.loadProgram = function(program) {
      for (var i = 0, length = program.length; i < length; i++) {
        this.memory[0x200 + i] = program[i];
      }
    }

    this.cycle = function() {
      for (var i = 0; i < this.speed; i++) {
        if (!this.paused) {
          var opcode = this.memory[this.pc] << 8 | this.memory[this.pc + 1];
          this.perform(opcode);
          this.updateTimers();
        }
      }

      this.render();
    }

    this.perform = function(opcode) {
      this.pc += 2;

      var x = (opcode & 0x0F00) >> 8;
      var y = (opcode & 0x00F0) >> 4;

      switch (opcode & 0xF000) {
        case 0x000:
          switch(opcode) {
            case 0x00E0:
              this.screen.clear();
              break;

            case 0x00EE:
              this.stackPointer -= 1;
              this.pc = this.stack[this.stackPointer];
              break;
          }
          break;

        case 0xA000:
          this.i = opcode & 0x0FFF;
          break;

        case 0xB000:
          this.pc = (opcode & 0x0FFF) + this.v[0];
          break;

        case 0x1000:
          this.pc = opcode & 0x0FFF;
          break;

        case 0x2000:
          this.stack[this.stackPointer] = this.pc;
          this.stackPointer += 1;
          this.pc = opcode & 0x0FFF;
          break;

        case 0x3000:
          if (this.v[x] == (opcode & 0x00FF)) {
            this.pc += 2;
          }
          break;

        case 0x4000:
          if (this.v[x] != (opcode & 0x00FF)) {
            this.pc += 2;
          }
          break;

        case 0x5000:
          if (this.v[x] == this.v[y]) {
            this.pc += 2;
          }
          break;

        case 0x6000:
          this.v[x] = opcode & 0x00FF;
          break;

        case 0x7000:
          this.v[x] += opcode & 0x00FF;
          break;

        case 0x8000:
          switch (opcode & 0x000F) {
            case 0x0000:
              this.v[x] = this.v[y];
              break;

            case 0x0001:
              this.v[x] = this.v[x] | this.v[y];
              break;

            case 0x0002:
              this.v[x] = this.v[x] & this.v[y];
              break;

            case 0x0003:
              this.v[x] = this.v[x] ^ this.v[y];
              break;

            case 0x0004:
              var sum = this.v[x] + this.v[y];

              if (sum > 0xFF) {
                this.v[0xF] = 1;
              } else {
                this.v[0xF] = 0;
              }

              this.v[x] = sum;
              break;

            case 0x0005:
              if(this.v[x] > this.v[y]) {
                this.v[0xF] = 1;
              } else {
                this.v[0xF] = 0;
              }

              this.v[x] = this.v[x] - this.v[y];
              break;

            case 0x0006:
              this.v[0xF] = this.v[x] & 0x01;
              this.v[x] = this.v[x] >> 1;
              break;

            case 0x0007:
              if (this.v[x] > this.v[y]) {
                this.v[0xF] = 0;
              } else {
                this.v[0xF] = 1;
              }

              this.v[x] = this.v[y] - this.v[x];
              break;

            case 0x000E:
              this.v[0xF] = this.v[x] & 0x80;
              this.v[x] = this.v[x] << 1;
              break;
          }
          break;

        case 0x9000:
          if (this.v[x] != this.v[y]) this.pc += 2;
          break;

        case 0xC000:
          this.v[x] = Math.floor(Math.random() * 0xFF) & (opcode & 0x00FF);
          break;

        case 0xD000:
          var row, col, sprite
            , width = 8
            , height = opcode & 0x000F;

          this.v[0xF] = 0;

          for (row = 0; row < height; row++) {
            sprite = this.memory[this.i + row];

            for (col = 0; col < width; col++) {
              if ((sprite & 0x80) > 0) {
                if (this.screen.setPixel(this.v[x] + col, this.v[y] + row)) {
                  this.v[0xF] = 1;
                }
              }

              sprite = sprite << 1;
            }
          }

          break;

        case 0xE000:
          switch (opcode & 0x00FF) {
            case 0x009E:
              if (this.input.isKeyPressed(this.v[x])) {
                this.pc += 2;
              }
              break;

            case 0x00A1:
              if (!this.input.isKeyPressed(this.v[x])) {
                this.pc += 2;
              }
              break;
          }
          break;

        case 0xF000:
          switch (opcode & 0x00FF) {
            case 0x0007:
              this.v[x] = this.delayTimer;
              break;

            case 0x000A:
              this.paused = true;

              this.input.onKeyPress = function(key) {
                this.v[x] = key;
                this.paused = false;
                this.input.onKeyPress = function() {}
              }.bind(this);

            case 0x0015:
              this.delayTimer = this.v[x];
              break;

            case 0x0018:
              this.soundTimer = this.v[x];
              break;

            case 0x0029:
              this.i = this.v[x] * 5;
              break;

            case 0x0033:
              this.memory[this.i]     = parseInt(this.v[x] / 100);
              this.memory[this.i + 1] = parseInt(this.v[x] % 100 / 10);
              this.memory[this.i + 2] = this.v[x] % 10;
              break;

            case 0x0055:
              for (var i = 0; i <= x; i++) {
                this.memory[this.i + i] = this.v[i];
              }
              break;

            case 0x0065:
              for (var i = 0; i <= x; i++) {
                this.v[i] = this.memory[this.i + i];
              }
              break;

            case 0x001E:
              this.i += this.v[x];
              break;
          }

          break;

        default:
          throw new Error("Unknow opcode " + opcode.toString(16) + " informed.");
      }
    }

    this.render = function() {
      this.screen.render();
    }

    this.updateTimers = function() {
      if (this.delayTimer > 0) this.delayTimer -= 1;
      if (this.soundTimer > 0) this.soundTimer -= 1;
    }
  }

  if (typeof module != "undefined") {
    module.exports = VM;
  } else {
    window.Chip8.VM = VM;
  }
})();
<|endoftext|>


<commit_before>import { Component, ApplicationRef, NgZone } from '@angular/core';

import path from 'path';
import fs from 'fs';
import $ from 'jquery';
import { remote, app, shell } from 'electron'; // native electron module
import jetpack from 'fs-jetpack'; // module loaded from npm
import Docxtemplater from 'docxtemplater';
var Handsontable = require('./handsontablep/dist/handsontable.full.js');
import { apbdesImporterConfig, Importer } from '../helpers/importer';
import { exportApbdes } from '../helpers/exporter';
import dataapi from '../stores/dataapi';
import schemas from '../schemas';
import { initializeTableSearch, initializeTableCount, initializeTableSelected } from '../helpers/table';
import diffProps from '../helpers/apbdesDiff';

window.jQuery = $;
require('./node_modules/bootstrap/dist/js/bootstrap.js');

var app = remote.app;
var hot;

var init = function() {
    window.addEventListener('resize', function(e){
        if(hot)
            hot.render();
    })
    $('.modal').each(function(i, modal){
        $(modal).on('hidden.bs.modal', function () {
            if(hot)
                hot.listen();
        })
    });
    schemas.registerCulture(window);
}

class SumCounter {
    constructor(hot){
        this.hot = hot;
        this.sums = {};
    }

    calculateAll(){
        var rows = this.hot.getSourceData().map(a => schemas.arrayToObj(a, schemas.apbdes));
        this.sums = {};
        for(var i = 0; i < rows.length; i++){
            var row = rows[i];
            if(row.kode_rekening && !this.sums[row.kode_rekening]){
                this.getValue(row, i, rows);
            }
        }
    }

    getValue(row, index, rows){
        if(Number.isFinite(row.anggaran)){
            if(row.kode_rekening){
                this.sums[row.kode_rekening] = row.anggaran;
            }
            return row.anggaran;
        }
        var sum = 0;
        var dotCount = row.kode_rekening.split(".").length;
        var i = index + 1;
        var allowDetail = true;
        while(i < rows.length){
            var nextRow  = rows[i];
            var nextDotCount = nextRow.kode_rekening ? nextRow.kode_rekening.split(".").length : 0;
            if(!nextRow.kode_rekening && allowDetail){
                if(Number.isFinite(nextRow.anggaran)){
                    sum += nextRow.anggaran;
                }
            } else if(nextRow.kode_rekening && nextRow.kode_rekening.startsWith(row.kode_rekening) && (dotCount + 1 == nextDotCount)){
                allowDetail = false;
                sum += this.getValue(nextRow, i, rows);
            } else if(nextRow.kode_rekening && !nextRow.kode_rekening.startsWith(row.kode_rekening) ){
                break;
            }
            i++;
        }
        this.sums[row.kode_rekening] = sum;
        return sum;
    }

    calculateBottomUp(index){
    }

}

var initSheet = function (subType) {
    var sheetContainer = document.getElementById('sheet-'+subType);
    var result = new Handsontable(sheetContainer, {
        data: [],
        topOverlay: 34,

        rowHeaders: true,
        colHeaders: schemas.getHeader(schemas.apbdes),
        columns: schemas.apbdes,

        colWidths: schemas.getColWidths(schemas.apbdes),
        rowHeights: 23,

        //columnSorting: true,
        //sortIndicator: true,

        renderAllRows: false,
        outsideClickDeselects: false,
        autoColumnSize: false,
        search: true,
        //filters: true,
        contextMenu: ['row_above', 'remove_row'],
        //dropdownMenu: ['filter_by_condition', 'filter_action_bar'],
    });
    result.sumCounter = new SumCounter(result);
    result.addHook('afterChange', function(changes, source){
        if (source === 'edit' || source === 'undo' || source === 'autofill') {
            var rerender = false;
            changes.forEach(function(item){
                 var row = item[0],
                    col = item[1],
                    prevValue = item[2],
                    value = item[3];

                 if(col == 2){
                    rerender = true;
                 }
            });
            if(rerender){
                result.sumCounter.calculateAll();
                result.render();
            }
        }
    });
    return result;
};

var isCodeLesserThan = function(code1, code2){
    if(!code2)
        return false;
    var splitted1 = code1.split(".").map(s => parseInt(s));
    var splitted2 = code2.split(".").map(s => parseInt(s));
    var min = Math.min(splitted1.length, splitted2.length);
    for(var i = 0; i < min; i++){
        if(splitted1[i] > splitted2[i]){
            return false;
        }
        if(splitted1[i] < splitted2[i]){
            return true;
        }
    }

    if(splitted1.length < splitted2.length)
        return true;

    return false;
};

var createDefaultApbdes = function(){
    return [
        ["1", "Pendapatan"],
        ["1.1", "Pendapatan Asli Desa"],
        ["1.1.1", "Hasil Usaha Desa"],
        ["1.2", "Pendapatan Transfer"],
        ["1.2.1", "Dana Desa"],
        ["1.2.2", "Bagian dari Hasil Pajak & Retribusi Daerah Kabupaten/Kota"],
        ["1.2.3", "Alokasi Dana Desa"],
        ["1.2.4", "Bantuan Keuangan"],
        ["1.2.4.1", "Bantuan Keuangan dari APBD Propinsi"],
        ["1.2.4.2", "Bantuan Keuangan dari APBD Kabupaten"],
        ["1.3", "Lain-lain Pendapatan Desa yang Sah"],
        ["1.3.1", "Hibah dan Sumbangan dari Pihak Ke-3 yang Tidak Mengikat"],
        ["2", "Belanja"],
        ["2.1", "Bidang Penyelenggaraan Pemerintah Desa"],
        ["2.2", "Bidang Pelaksanaan Pembangunan Desa"],
        ["2.3", "Bidang Pembinaan Kemasyarakatan"],
        ["2.4", "Bidang Pemberdayaan Masyarakat"],
        ["3", "Pembiayaan"],
        ["3.1", "Penerimaan Pembiayaan"],
        ["3.1.1", "SILPA"],
        ["3.1.2", "Pencairan Dana Cadangan"],
        ["3.1.3", "Hasil Kekayaan Desa yang Dipisahkan"],
        ["3.2", "Pengeluaran Pembiayaan"],
        ["3.2.1", "Pembentukan Dana Cadangan"],
        ["3.2.2", "Penyertaan Modal Desa"],
    ];
}

var ApbdesComponent = Component({
    selector: 'apbdes',
    templateUrl: 'templates/apbdes.html'
})
.Class(Object.assign(diffProps, {
    constructor: function(appRef, zone) {
        this.appRef = appRef;
        this.zone = zone;
    },
    ngOnInit: function(){
        $("title").html("APBDes - " +dataapi.getActiveAuth().desa_name);
        init();

        this.importer = new Importer(apbdesImporterConfig);
        this.hots = {};
        this.tableSearchers = {};
        this.initialDatas = {};
        var ctrl = this;

        function keyup(e) {
            //ctrl+s
            if (e.ctrlKey && e.keyCode == 83){
                ctrl.openSaveDiffDialog();
                e.preventDefault();
                e.stopPropagation();
            }
        }
        document.addEventListener('keyup', keyup, false);

        this.activeSubType = null;
        dataapi.getContentSubTypes("apbdes", subTypes => {
            this.subTypes = subTypes;
            this.appRef.tick();
            if(this.subTypes.length)
                this.loadSubType(subTypes[0]);
        });
        this.initDiffComponent(true);
    },
    loadSubType(subType){
        if(!this.hots[subType]){
            this.hots[subType] = initSheet(subType);
            this.hot = hot = this.hots[subType];
            var inputSearch = document.getElementById("input-search-"+subType);
            this.tableSearchers[subType] = initializeTableSearch(hot, document, inputSearch, () => this.activeSubType == subType);
            this.tableSearcher = this.tableSearchers[subType];

            dataapi.getContent("apbdes", subType, [], content => {
                this.zone.run( () => {
                    this.activeSubType = subType;
                    this.initialDatas[subType] = JSON.parse(JSON.stringify(content.data));

                    this.hot.loadData(content.data);
                    this.hot.sumCounter.calculateAll();
                    this.hot.validateCells();
                    setTimeout(() => {
                        this.hot.render();
                    },500);
                });
            });
        } else {
            this.hot = hot = this.hots[subType];
            this.tableSearcher = this.tableSearchers[subType];
            this.activeSubType = subType;
            this.hot.render();
        }
        return false;
    },
    importExcel: function(){
        var files = remote.dialog.showOpenDialog();
        if(files && files.length){
            this.importer.init(files[0]);
            $("#modal-import-columns").modal("show");
        }
    },
    doImport: function(){
        $("#modal-import-columns").modal("hide");
        var objData = this.importer.getResults();
        var data = objData.map(o => schemas.objToArray(o, schemas.apbdes));

        hot.loadData(data);
        hot.sumCounter.calculateAll();
        hot.validateCells();
        setTimeout(function(){
            hot.render();
        },500);
    },
    exportExcel: function(){
        var data = hot.getSourceData();
        for(var i = 0; i < data.length; i++){
            var row = data[i];
            var value = row[2];
            if(!Number.isFinite(value) && !value){
                var code = row[0];
                if(code){
                    row[2] = hot.sumCounter.sums[code];
                }
            }
        }
        exportApbdes(data, "Apbdes");
    },
    openAddRowDialog: function(){
        $("#modal-add").modal("show");
        setTimeout(() => {
            this.hot.unlisten();
            $("input[name='account_code']").focus();
        }, 500);
        return false;
    },
    addRow: function(){
        var data = $("#form-add").serializeArray().map(i => i.value);
        var sourceData = hot.getSourceData();
        var position = 0;
        for(;position < sourceData.length; position++){
            if(isCodeLesserThan(data[0], sourceData[position][0]))
                break;
        };
        if(data[1]=="on"){
            data[0]="";
            data.splice(1,1)
        };
        hot.alter("insert_row", position);
        hot.populateFromArray(position, 0, [data], position, 3, null, 'overwrite');
        hot.selection.setRangeStart(new WalkontableCellCoords(position,0));
        hot.selection.setRangeEnd(new WalkontableCellCoords(position,3));
        $('#form-add')[0].reset();
    },
    addOneRow: function(){
        this.addRow();
        $("#modal-add").modal("hide");
    },
    addOneRowAndAnother: function(){
        var code = $("input[name='account_code']").val();
        this.addRow();
        $("input[name='account_code']").focus().val(code).select();
        return false;
    },
    openNewSubTypeDialog: function(){
        $("#modal-new-year").modal("show");
        setTimeout(function(){
            if(hot)
                hot.unlisten();
            $("input[name='year']").focus();
        }, 500);
        return false;
    },
    createNewSubType: function(){
        var year = $("#form-new-year input[name='year']").val();
        var is_perubahan = $("#form-new-year input[name='is_perubahan']")[0].checked;
        var subType = year;
        if(is_perubahan)
            subType = subType+"p";

        //TODO: show error already exists
        if(this.subTypes.filter(s => s == subType).length)
            return;

        this.activeSubType = subType;
        this.subTypes.push(subType);
        this.appRef.tick();

        this.hots[subType] = initSheet(subType);
        this.hot = hot = this.hots[subType];
        hot.loadData(createDefaultApbdes());
        hot.sumCounter.calculateAll();
        hot.validateCells();
        this.initialDatas[subType] = [];

        var inputSearch = document.getElementById("input-search-"+subType);
        this.tableSearchers[subType] = initializeTableSearch(hot, document, inputSearch, () => this.activeSubType == subType);
        this.tableSearcher = this.tableSearchers[subType];

        $("#modal-new-year").modal("hide");
        return false;
    },
    saveContent: function(){
        $("#modal-save-diff").modal("hide");
        var count = 0;
        this.diffs.subTypes.filter(s => this.diffs.diffs[s].total).forEach(subType => {
            count += 1;
            var timestamp = new Date().getTime();
            var content = {
                timestamp: timestamp,
                data: hot.getSourceData()
            };

            var that = this;
            that.savingMessage = "Menyimpan...";
            dataapi.saveContent("apbdes", subType, content, function(err, response, body){
                count -= 1;
                that.savingMessage = "Penyimpanan "+ (err ? "gagal" : "berhasil");
                if(!err){
                    that.initialDatas[subType] = JSON.parse(JSON.stringify(content.data));
                    if(count == 0)
                        that.afterSave();
                }
                setTimeout(function(){
                    that.savingMessage = null;
                }, 2000);
            });
        });
        return false;
    }
}));
ApbdesComponent.parameters = [ApplicationRef, NgZone];

export default ApbdesComponent;<commit_msg>anggaran validator<commit_after>import { Component, ApplicationRef, NgZone } from '@angular/core';

import path from 'path';
import fs from 'fs';
import $ from 'jquery';
import { remote, app, shell } from 'electron'; // native electron module
import jetpack from 'fs-jetpack'; // module loaded from npm
import Docxtemplater from 'docxtemplater';
var Handsontable = require('./handsontablep/dist/handsontable.full.js');
import { apbdesImporterConfig, Importer } from '../helpers/importer';
import { exportApbdes } from '../helpers/exporter';
import dataapi from '../stores/dataapi';
import schemas from '../schemas';
import { initializeTableSearch, initializeTableCount, initializeTableSelected } from '../helpers/table';
import diffProps from '../helpers/apbdesDiff';

window.jQuery = $;
require('./node_modules/bootstrap/dist/js/bootstrap.js');

var app = remote.app;
var hot;

var init = function() {
    window.addEventListener('resize', function(e){
        if(hot)
            hot.render();
    })
    $('.modal').each(function(i, modal){
        $(modal).on('hidden.bs.modal', function () {
            if(hot)
                hot.listen();
        })
    });
    schemas.registerCulture(window);
}

class SumCounter {
    constructor(hot){
        this.hot = hot;
        this.sums = {};
    }

    calculateAll(){
        var rows = this.hot.getSourceData().map(a => schemas.arrayToObj(a, schemas.apbdes));
        this.sums = {};
        for(var i = 0; i < rows.length; i++){
            var row = rows[i];
            if(row.kode_rekening && !this.sums[row.kode_rekening]){
                this.getValue(row, i, rows);
            }
        }
    }

    getValue(row, index, rows){
        var sum = 0;
        var dotCount = row.kode_rekening.split(".").length;
        var i = index + 1;
        var allowDetail = true;
        while(i < rows.length){
            var nextRow  = rows[i];
            var nextDotCount = nextRow.kode_rekening ? nextRow.kode_rekening.split(".").length : 0;
            if(!nextRow.kode_rekening && allowDetail){
                if(Number.isFinite(nextRow.anggaran)){
                    sum += nextRow.anggaran;
                }
            } else if(nextRow.kode_rekening && nextRow.kode_rekening.startsWith(row.kode_rekening) && (dotCount + 1 == nextDotCount)){
                allowDetail = false;
                sum += this.getValue(nextRow, i, rows);
            } else if(nextRow.kode_rekening && !nextRow.kode_rekening.startsWith(row.kode_rekening) ){
                break;
            }
            i++;
        }
        this.sums[row.kode_rekening] = sum;
        if(Number.isFinite(row.anggaran)){
            if(sum == 0 && row.kode_rekening){
                //this.sums[row.kode_rekening] = row.anggaran;
            }
            return row.anggaran;
        }
        return sum;
    }

    calculateBottomUp(index){
    }

}

var initSheet = function (subType) {
    var sheetContainer = document.getElementById('sheet-'+subType);
    var result = new Handsontable(sheetContainer, {
        data: [],
        topOverlay: 34,

        rowHeaders: true,
        colHeaders: schemas.getHeader(schemas.apbdes),
        columns: schemas.apbdes,

        colWidths: schemas.getColWidths(schemas.apbdes),
        rowHeights: 23,

        //columnSorting: true,
        //sortIndicator: true,

        renderAllRows: false,
        outsideClickDeselects: false,
        autoColumnSize: false,
        search: true,
        //filters: true,
        contextMenu: ['row_above', 'remove_row'],
        //dropdownMenu: ['filter_by_condition', 'filter_action_bar'],
    });
    result.sumCounter = new SumCounter(result);
    result.addHook('afterChange', function(changes, source){
        if (source === 'edit' || source === 'undo' || source === 'autofill') {
            var rerender = false;
            changes.forEach(function(item){
                 var row = item[0],
                    col = item[1],
                    prevValue = item[2],
                    value = item[3];

                 if(col == 2){
                    rerender = true;
                 }
            });
            if(rerender){
                result.sumCounter.calculateAll();
                result.render();
            }
        }
    });
    return result;
};

var isCodeLesserThan = function(code1, code2){
    if(!code2)
        return false;
    var splitted1 = code1.split(".").map(s => parseInt(s));
    var splitted2 = code2.split(".").map(s => parseInt(s));
    var min = Math.min(splitted1.length, splitted2.length);
    for(var i = 0; i < min; i++){
        if(splitted1[i] > splitted2[i]){
            return false;
        }
        if(splitted1[i] < splitted2[i]){
            return true;
        }
    }

    if(splitted1.length < splitted2.length)
        return true;

    return false;
};

var createDefaultApbdes = function(){
    return [
        ["1", "Pendapatan"],
        ["1.1", "Pendapatan Asli Desa"],
        ["1.1.1", "Hasil Usaha Desa"],
        ["1.2", "Pendapatan Transfer"],
        ["1.2.1", "Dana Desa"],
        ["1.2.2", "Bagian dari Hasil Pajak & Retribusi Daerah Kabupaten/Kota"],
        ["1.2.3", "Alokasi Dana Desa"],
        ["1.2.4", "Bantuan Keuangan"],
        ["1.2.4.1", "Bantuan Keuangan dari APBD Propinsi"],
        ["1.2.4.2", "Bantuan Keuangan dari APBD Kabupaten"],
        ["1.3", "Lain-lain Pendapatan Desa yang Sah"],
        ["1.3.1", "Hibah dan Sumbangan dari Pihak Ke-3 yang Tidak Mengikat"],
        ["2", "Belanja"],
        ["2.1", "Bidang Penyelenggaraan Pemerintah Desa"],
        ["2.2", "Bidang Pelaksanaan Pembangunan Desa"],
        ["2.3", "Bidang Pembinaan Kemasyarakatan"],
        ["2.4", "Bidang Pemberdayaan Masyarakat"],
        ["3", "Pembiayaan"],
        ["3.1", "Penerimaan Pembiayaan"],
        ["3.1.1", "SILPA"],
        ["3.1.2", "Pencairan Dana Cadangan"],
        ["3.1.3", "Hasil Kekayaan Desa yang Dipisahkan"],
        ["3.2", "Pengeluaran Pembiayaan"],
        ["3.2.1", "Pembentukan Dana Cadangan"],
        ["3.2.2", "Penyertaan Modal Desa"],
    ];
}

var ApbdesComponent = Component({
    selector: 'apbdes',
    templateUrl: 'templates/apbdes.html'
})
.Class(Object.assign(diffProps, {
    constructor: function(appRef, zone) {
        this.appRef = appRef;
        this.zone = zone;
    },
    ngOnInit: function(){
        $("title").html("APBDes - " +dataapi.getActiveAuth().desa_name);
        init();

        this.importer = new Importer(apbdesImporterConfig);
        this.hots = {};
        this.tableSearchers = {};
        this.initialDatas = {};
        var ctrl = this;

        function keyup(e) {
            //ctrl+s
            if (e.ctrlKey && e.keyCode == 83){
                ctrl.openSaveDiffDialog();
                e.preventDefault();
                e.stopPropagation();
            }
        }
        document.addEventListener('keyup', keyup, false);

        this.activeSubType = null;
        dataapi.getContentSubTypes("apbdes", subTypes => {
            this.subTypes = subTypes;
            this.appRef.tick();
            if(this.subTypes.length)
                this.loadSubType(subTypes[0]);
        });
        this.initDiffComponent(true);
    },
    loadSubType(subType){
        if(!this.hots[subType]){
            this.hots[subType] = initSheet(subType);
            this.hot = hot = this.hots[subType];
            var inputSearch = document.getElementById("input-search-"+subType);
            this.tableSearchers[subType] = initializeTableSearch(hot, document, inputSearch, () => this.activeSubType == subType);
            this.tableSearcher = this.tableSearchers[subType];

            dataapi.getContent("apbdes", subType, [], content => {
                this.zone.run( () => {
                    this.activeSubType = subType;
                    this.initialDatas[subType] = JSON.parse(JSON.stringify(content.data));

                    this.hot.loadData(content.data);
                    this.hot.sumCounter.calculateAll();
                    this.hot.validateCells();
                    setTimeout(() => {
                        this.hot.render();
                    },500);
                });
            });
        } else {
            this.hot = hot = this.hots[subType];
            this.tableSearcher = this.tableSearchers[subType];
            this.activeSubType = subType;
            this.hot.render();
        }
        return false;
    },
    importExcel: function(){
        var files = remote.dialog.showOpenDialog();
        if(files && files.length){
            this.importer.init(files[0]);
            $("#modal-import-columns").modal("show");
        }
    },
    doImport: function(){
        $("#modal-import-columns").modal("hide");
        var objData = this.importer.getResults();
        var data = objData.map(o => schemas.objToArray(o, schemas.apbdes));

        hot.loadData(data);
        hot.sumCounter.calculateAll();
        hot.validateCells();
        setTimeout(function(){
            hot.render();
        },500);
    },
    exportExcel: function(){
        var data = hot.getSourceData();
        for(var i = 0; i < data.length; i++){
            var row = data[i];
            var value = row[2];
            if(!Number.isFinite(value) && !value){
                var code = row[0];
                if(code){
                    row[2] = hot.sumCounter.sums[code];
                }
            }
        }
        exportApbdes(data, "Apbdes");
    },
    openAddRowDialog: function(){
        $("#modal-add").modal("show");
        setTimeout(() => {
            this.hot.unlisten();
            $("input[name='account_code']").focus();
        }, 500);
        return false;
    },
    addRow: function(){
        var data = $("#form-add").serializeArray().map(i => i.value);
        var sourceData = hot.getSourceData();
        var position = 0;
        for(;position < sourceData.length; position++){
            if(isCodeLesserThan(data[0], sourceData[position][0]))
                break;
        };
        if(data[1]=="on"){
            data[0]="";
            data.splice(1,1)
        };
        hot.alter("insert_row", position);
        hot.populateFromArray(position, 0, [data], position, 3, null, 'overwrite');
        hot.selection.setRangeStart(new WalkontableCellCoords(position,0));
        hot.selection.setRangeEnd(new WalkontableCellCoords(position,3));
        $('#form-add')[0].reset();
    },
    addOneRow: function(){
        this.addRow();
        $("#modal-add").modal("hide");
    },
    addOneRowAndAnother: function(){
        var code = $("input[name='account_code']").val();
        this.addRow();
        $("input[name='account_code']").focus().val(code).select();
        return false;
    },
    openNewSubTypeDialog: function(){
        $("#modal-new-year").modal("show");
        setTimeout(function(){
            if(hot)
                hot.unlisten();
            $("input[name='year']").focus();
        }, 500);
        return false;
    },
    createNewSubType: function(){
        var year = $("#form-new-year input[name='year']").val();
        var is_perubahan = $("#form-new-year input[name='is_perubahan']")[0].checked;
        var subType = year;
        if(is_perubahan)
            subType = subType+"p";

        //TODO: show error already exists
        if(this.subTypes.filter(s => s == subType).length)
            return;

        this.activeSubType = subType;
        this.subTypes.push(subType);
        this.appRef.tick();

        this.hots[subType] = initSheet(subType);
        this.hot = hot = this.hots[subType];
        hot.loadData(createDefaultApbdes());
        hot.sumCounter.calculateAll();
        hot.validateCells();
        this.initialDatas[subType] = [];

        var inputSearch = document.getElementById("input-search-"+subType);
        this.tableSearchers[subType] = initializeTableSearch(hot, document, inputSearch, () => this.activeSubType == subType);
        this.tableSearcher = this.tableSearchers[subType];

        $("#modal-new-year").modal("hide");
        return false;
    },
    saveContent: function(){
        $("#modal-save-diff").modal("hide");
        var count = 0;
        this.diffs.subTypes.filter(s => this.diffs.diffs[s].total).forEach(subType => {
            count += 1;
            var timestamp = new Date().getTime();
            var content = {
                timestamp: timestamp,
                data: hot.getSourceData()
            };

            var that = this;
            that.savingMessage = "Menyimpan...";
            dataapi.saveContent("apbdes", subType, content, function(err, response, body){
                count -= 1;
                that.savingMessage = "Penyimpanan "+ (err ? "gagal" : "berhasil");
                if(!err){
                    that.initialDatas[subType] = JSON.parse(JSON.stringify(content.data));
                    if(count == 0)
                        that.afterSave();
                }
                setTimeout(function(){
                    that.savingMessage = null;
                }, 2000);
            });
        });
        return false;
    }
}));
ApbdesComponent.parameters = [ApplicationRef, NgZone];

export default ApbdesComponent;<|endoftext|>


<commit_before>import React from 'react';

class ButtonPage extends React.Component {
  static getInitialProps ({ query: { color, collectiveSlug, verb } }) {
    return { color, collectiveSlug, verb }
  }

  render() {
    const { color = 'white', collectiveSlug, verb = 'donate' } = this.props;

    return (

        <a type="button" className={`btn ${color} ${verb}`} target="_blank" rel="noopener noreferrer" href={`https://opencollective.com/${collectiveSlug}/${verb}`} />

    );
  }
}

export default ButtonPage;
<commit_msg>fix(pages/button): create unique class name to avoid bootstrap clash<commit_after>import React from 'react';

class ButtonPage extends React.Component {
  static getInitialProps ({ query: { color, collectiveSlug, verb } }) {
    return { color, collectiveSlug, verb }
  }

  render() {
    const { color = 'white', collectiveSlug, verb = 'donate' } = this.props;

    return (

        <a type="button" className={`collect-btn ${color} ${verb}`} target="_blank" rel="noopener noreferrer" href={`https://opencollective.com/${collectiveSlug}/${verb}`} />

    );
  }
}

export default ButtonPage;
<|endoftext|>