<commit_before>import { ipcMain, dialog } from 'electron'
import fs from 'fs'
import path from 'path'
import jsonfile from 'jsonfile'
import ProductValidator from './validator.js'

// set indentation for jsonfile
jsonfile.spaces = 2

// choose the _data directory
ipcMain.on('choose-data-dir', event => {
  // dialog.showOpenDialog always returns an array of files/dirs!
  dialog.showOpenDialog({ properties: ['openDirectory'] }, dataDirs => {
    if (!dataDirs) return
    const dataDir = dataDirs[0]
    event.sender.send('data-dir-choosen', dataDir)
  })
})

// load and send productSchema
ipcMain.on('fetch-product-schema', (event, dataDir) => {
  try {
    const productSchema = jsonfile.readFileSync(`${dataDir}/prod.schema.json`)
    // keys are needed to reorder properties, see comment below
    const keys = Object.keys(productSchema.properties)

    // all arguments to event.sender.send will be serialized to json internally!
    // https://github.com/electron/electron/blob/master/docs/api/ipc-renderer.md
    // So the order get lost in ipc... Reorder on the other side!!!
    event.sender.send('product-schema-fetched', productSchema, keys)
  } catch (err) {
    event.sender.send(
      'error-fetching-product-schema',
      `Error: ${err}`
    )
  }
})

// load and send all products
ipcMain.on('fetch-all-products', (event, dataDir) => {
  try {
    const productSchema = jsonfile.readFileSync(`${dataDir}/prod.schema.json`)

    // pass config object to ProductValidator's constructor
    const productValidator = new ProductValidator({
      dataDir,
      productSchema
    })

    const orderedFixedProducts = productValidator
      .validateAllProducts()
      .fixAllProducts()
      .orderFixedProducts()
      .saveOrderedFixedProducts()
      .orderedFixedProducts

    // all arguments to event.sender.send will be serialized to json internally!
    // https://github.com/electron/electron/blob/master/docs/api/ipc-renderer.md
    // So the order get lost in ipc... Reorder on the other side!!!
    event.sender.send('all-products-fetched', orderedFixedProducts)
  } catch (err) {
    event.sender.send(
      'error-fetching-prods',
      `Error: ${err}`
    )
  }
})

// load and send all nutrients
ipcMain.on('fetch-all-nutrients', (event, dataDir) => {
  try {
    const nutrientFileNames = fs.readdirSync(`${dataDir}/nutrs`)
    .filter(filename => {
      // json files only...
      const extension = path.extname(filename)
      return extension === '.json'
    })

    const allNutrients = nutrientFileNames
    .map(filename => {
      return jsonfile.readFileSync(`${dataDir}/nutrs/${filename}`)
    })

    event.sender.send('all-nutrients-fetched', allNutrients)
  } catch (err) {
    event.sender.send(
      'error-fetching-nutrients',
      `Error: ${err}`
    )
  }
})

// load and send all faos
ipcMain.on('fetch-all-faos', (event, dataDir) => {
  try {
    const allFAOs = jsonfile.readFileSync(`${dataDir}/fao-product-list.json`)
    event.sender.send('all-faos-fetched', allFAOs)
  } catch (err) {
    event.sender.send(
      'error-fetching-faos',
      `Error: ${err}`
    )
  }
})

// HACK: save all products is triggered when a single product was edited or
// added and saved. This ensures that all new products are validated and/or
// fixed upon save and show up in the invalid product view when invalid
ipcMain.on('save-all-products', (event, dataDir, products) => {
  try {
    const productSchema = jsonfile.readFileSync(`${dataDir}/prod.schema.json`)

    // pass config object to ProductValidator's constructor
    const productValidator = new ProductValidator({
      dataDir,
      productSchema
    })

    const orderedFixedProducts = productValidator
      .setProducts(products)
      .validateAllProducts()
      .fixAllProducts()
      .orderFixedProducts()
      .saveOrderedFixedProducts()
      .orderedFixedProducts

    // send fixed products back so they can be put to the redux store.
    // All arguments to event.sender.send will be serialized to json
    // internally! So the order get lost in ipc... Reorder on the other
    // side!!!
    event.sender.send('all-products-saved', orderedFixedProducts)
  } catch (err) {
    event.sender.send(
      'error-saving-products',
      `Error: ${err}`
    )
  }
})

ipcMain.on('save-edited-product', (event, dataDir, editedProduct) => {
  try {
    const productSchema = jsonfile.readFileSync(`${dataDir}/prod.schema.json`)

    // pass config object to ProductValidator's constructor
    const productValidator = new ProductValidator({
      dataDir,
      productSchema
    })

    productValidator
      .setProduct(editedProduct)
      .validateProduct()
      .orderValidatedProduct()
      .saveOrderedValidatedProduct()

    event.sender.send('edited-product-saved')
  } catch (err) {
    event.sender.send(
      'error-saving-product',
      `Error: ${err}`
    )
  }
})
<commit_msg>Let error.stack bubble up<commit_after>import { ipcMain, dialog } from 'electron'
import fs from 'fs'
import path from 'path'
import jsonfile from 'jsonfile'
import ProductValidator from '../validator/validator'

// set indentation for jsonfile
jsonfile.spaces = 2

// choose the _data directory
ipcMain.on('choose-data-dir', event => {
  // dialog.showOpenDialog always returns an array of files/dirs!
  dialog.showOpenDialog({ properties: ['openDirectory'] }, dataDirs => {
    if (!dataDirs) return
    const dataDir = dataDirs[0]
    event.sender.send('data-dir-choosen', dataDir)
  })
})

// load and send productSchema
ipcMain.on('fetch-product-schema', (event, dataDir) => {
  try {
    const productSchema = jsonfile.readFileSync(`${dataDir}/prod.schema.json`)
    // keys are needed to reorder properties, see comment below
    const keys = Object.keys(productSchema.properties)

    // all arguments to event.sender.send will be serialized to json internally!
    // https://github.com/electron/electron/blob/master/docs/api/ipc-renderer.md
    // So the order get lost in ipc... Reorder on the other side!!!
    event.sender.send('product-schema-fetched', productSchema, keys)
  } catch (err) {
    event.sender.send(
      'error-fetching-product-schema',
      `Error: ${err.stack.stack}`
    )
  }
})

// load and send all products
ipcMain.on('fetch-all-products', (event, dataDir) => {
  try {
    const productValidator = new ProductValidator(dataDir)

    const orderedFixedProducts = productValidator
      .loadAll()
      .validateAllProducts()
      .fixAllProducts()
      .orderFixedProducts()
      .saveOrderedFixedProducts()
      .orderedFixedProducts

    // all arguments to event.sender.send will be serialized to json internally!
    // https://github.com/electron/electron/blob/master/docs/api/ipc-renderer.md
    // So the order get lost in ipc... Reorder on the other side!!!
    event.sender.send('all-products-fetched', orderedFixedProducts)
  } catch (err) {
    event.sender.send(
      'error-fetching-prods',
      `Error: ${err.stack}`
    )
  }
})

// load and send all nutrients
ipcMain.on('fetch-all-nutrients', (event, dataDir) => {
  try {
    const nutrientFileNames = fs.readdirSync(`${dataDir}/nutrs`)
    .filter(filename => {
      // json files only...
      const extension = path.extname(filename)
      return extension === '.json'
    })

    const allNutrients = nutrientFileNames
    .map(filename => {
      return jsonfile.readFileSync(`${dataDir}/nutrs/${filename}`)
    })

    event.sender.send('all-nutrients-fetched', allNutrients)
  } catch (err) {
    event.sender.send(
      'error-fetching-nutrients',
      `Error: ${err.stack}`
    )
  }
})

// load and send all faos
ipcMain.on('fetch-all-faos', (event, dataDir) => {
  try {
    const allFAOs = jsonfile.readFileSync(`${dataDir}/fao-product-list.json`)
    event.sender.send('all-faos-fetched', allFAOs)
  } catch (err) {
    event.sender.send(
      'error-fetching-faos',
      `Error: ${err.stack}`
    )
  }
})

// HACK: save all products is triggered when a single product was edited or
// added and saved. This ensures that all new products are validated and/or
// fixed upon save and show up in the invalid product view when invalid
ipcMain.on('save-all-products', (event, dataDir, products) => {
  try {
    const productValidator = new ProductValidator(dataDir)

    const orderedFixedProducts = productValidator
      .loadAll()
      .setProducts(products)
      .validateAllProducts()
      .fixAllProducts()
      .orderFixedProducts()
      .saveOrderedFixedProducts()
      .orderedFixedProducts

    // send fixed products back so they can be put to the redux store.
    // All arguments to event.sender.send will be serialized to json
    // internally! So the order get lost in ipc... Reorder on the other
    // side!!!
    event.sender.send('all-products-saved', orderedFixedProducts)
  } catch (err) {
    event.sender.send(
      'error-saving-products',
      `Error: ${err.stack}`
    )
  }
})

ipcMain.on('save-edited-product', (event, dataDir, editedProduct) => {
  try {
    const productValidator = new ProductValidator(dataDir)

    productValidator
      .loadAll()
      .setProduct(editedProduct)
      .validateProduct()
      .orderValidatedProduct()
      .saveOrderedValidatedProduct()

    event.sender.send('edited-product-saved')
  } catch (err) {
    event.sender.send(
      'error-saving-product',
      `Error: ${err.stack}`
    )
  }
})
<|endoftext|>


<commit_before>/* global angular */
angular.module('suite')
    .factory('StringsFactory', [function() {
        return {
            /**
            *  Convert a myriad of time strings to a proper date:
            *  '1:00 pm','1:00 p.m.','1:00 p','1:00pm',
            *  '1:00p.m.','1:00p','1 pm','1 p.m.','1 p',
            *  '1pm','1p.m.', '1p','13:00','13'
            */
            parseTime: function(timeString, day) {
                var timeDay = new Date(day);
                var time = timeString.match(/(\d+)(?::(\d\d))?\s*(p?)/);
                //Check if day is valid
                if (Object.prototype.toString.call(timeDay) === "[object Date]") {
                    timeDay = new Date();
                }
                timeDay.setHours(parseInt(time[1]) + (time[3] ? 12 : 0));
                timeDay.setMinutes(parseInt(time[2]) || 0);
                return timeDay;
            }
        };
    }
]);
<commit_msg>Date Parsing: fix 12 pm glitch<commit_after>/* global angular */
angular.module('suite')
    .factory('StringsFactory', [function() {
        return {
            /**
            *  Convert a myriad of time strings to a proper date:
            *  '1:00 pm','1:00 p.m.','1:00 p','1:00pm',
            *  '1:00p.m.','1:00p','1 pm','1 p.m.','1 p',
            *  '1pm','1p.m.', '1p','13:00','13'
            *   From: http://stackoverflow.com/questions/141348/what-is-the-best-way-to-parse-a-time-into-a-date-object-from-user-input-in-javas
            */
            parseTime: function(timeString, date) {
                var time, hours, d;
                if (timeString === '') {
                    return null;
                }

                d = new Date(date);

                if (Object.prototype.toString.call(d) === "[object Date]") {
                    d = new Date();
                }

                time = timeString.match(/(\d+)(:(\d\d))?\s*(p?)/i);
                if (time === null) {
                    return null;
                }

                hours = parseInt(time[1],10);
                if (hours === 12 && !time[4]) {
                    hours = 0;
                } else {
                    hours += (hours < 12 && time[4]) ? 12 : 0;
                }

                d.setHours(hours);
                d.setMinutes(parseInt(time[3],10) || 0);
                d.setSeconds(0, 0);
                return d;
            }
        };
    }
]);
<|endoftext|>


<commit_before>var FireWatch = require('../index');
var Fs = require('fire-fs');
var Path = require('fire-path');

function reset () {
    Fs.rimrafSync("./test/foobar/");
    Fs.copySync("./test/test-data/", "./test/foobar");
}

function printResults ( results ) {
    console.log();
    console.log("    ---------------- results ----------------");
    results.forEach( function ( item ) {
        var text = "    %s: %s " + (item.isDirectory ? "[folder]" : "");
        console.log( text, item.command, item.path );
    });
}
function mapResults ( results ) {
    return results.map( function ( item ) {
        item.path = Path.join(root, item.path);
        return item;
    });
}

var root = Fs.realpathSync("./test/foobar/");

describe('FireWatch Simple Case', function () {
    it('should work for new file', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start(root, function () {
            Fs.writeFileSync(Path.join(root, "foo/foo-01/foobar-new.js"), "Hello World!");
            Fs.writeFileSync(Path.join(root, "foo/foobar-new.js"), "Hello World!");
        });
        watcher.stop( function () { done(); } );
        watcher.on("changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "new", path: "foo/foo-01/foobar-new.js", isDirectory: false },
                { command: "new", path: "foo/foobar-new.js", isDirectory: false },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for new folder', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.mkdirSync(Path.join(root, "foo/foo-01-new"));
            Fs.mkdirSync(Path.join(root, "foo-new"));
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "new", path: "foo-new", isDirectory: true },
                { command: "new", path: "foo/foo-01-new", isDirectory: true },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for delete file', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.rimrafSync(Path.join(root, "foo/foobar.js"));
            Fs.rimrafSync(Path.join(root, "foo/foo-01/foobar.js"));
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "delete", path: "foo/foo-01/foobar.js", isDirectory: false },
                { command: "delete", path: "foo/foobar.js", isDirectory: false },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for delete folder', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.rimrafSync(Path.join(root, "foo/foo-01"));
            Fs.rimrafSync(Path.join(root, "bar"));
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "delete", path: "bar", isDirectory: true },
                { command: "delete", path: "foo/foo-01", isDirectory: true },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for rename file', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.renameSync( Path.join(root, "foo/foobar.js"),
                           Path.join(root, "foo/foobar-rename.js") );

            Fs.renameSync( Path.join(root, "foo/foo-01/foobar.js"),
                           Path.join(root, "bar/bar-01/foobar-rename.js") );

            Fs.renameSync( Path.join(root, "foo/foo-02/foobar.js"),
                           Path.join(root, "bar/bar-02/foobar-rename.js") );

            Fs.renameSync( Path.join(root, "foo/foo-03/foobar.js"),
                           Path.join(root, "bar/bar-02/foobar-rename.js") );
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "delete", path: "foo/foo-01/foobar.js", isDirectory: false },
                { command: "delete", path: "foo/foo-02/foobar.js", isDirectory: false },
                { command: "delete", path: "foo/foo-03/foobar.js", isDirectory: false },
                { command: "delete", path: "foo/foobar.js", isDirectory: false },
                { command: "new", path: "bar/bar-01/foobar-rename.js", isDirectory: false },
                { command: "new", path: "bar/bar-02/foobar-rename.js", isDirectory: false },
                { command: "new", path: "foo/foobar-rename.js", isDirectory: false },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for rename folder', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.renameSync( Path.join(root, "foo/foo-01"),
                           Path.join(root, "bar/bar-04") );
            Fs.renameSync( Path.join(root, "foo/foo-02"),
                           Path.join(root, "bar/bar-04/bar-02") );
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "delete", path: "foo/foo-01", isDirectory: true },
                { command: "delete", path: "foo/foo-02", isDirectory: true },
                { command: "new", path: "bar/bar-04", isDirectory: true },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for editing file', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.writeFileSync(Path.join(root,"foo/foobar.js"), "Hello World!");
            Fs.writeFileSync(Path.join(root,"foo/foo-02/foobar.js"), "Hello World!");
            Fs.writeFileSync(Path.join(root,"bar/bar-01/foobar-new.js"), "Hello World!");
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "new", path: "bar/bar-01/foobar-new.js", isDirectory: false },
                { command: "change", path: "foo/foo-02/foobar.js", isDirectory: false },
                { command: "change", path: "foo/foobar.js", isDirectory: false },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });
});

describe('FireWatch Compound Case', function () {
    it('should work for rename, new, delete, editing files', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.writeFileSync(Path.join(root,"foo/foobar.js"), "Hello World!");
            Fs.rimrafSync(Path.join(root, "foo/foobar.js"));

            Fs.writeFileSync(Path.join(root,"foo/foo-02/foobar.js"), "Hello World!");
            Fs.writeFileSync(Path.join(root,"bar/bar-01/foobar-new.js"), "Hello World!");

            Fs.renameSync( Path.join(root, "foo/foo-03/foobar.js"),
                           Path.join(root, "bar/bar-03/foobar-rename.js") );

            Fs.rimrafSync(Path.join(root, "foo/foo-01/foobar.js"));
            Fs.rimrafSync(Path.join(root, "bar/bar-03/foobar-rename.js"));
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "delete", path: "foo/foo-01/foobar.js", isDirectory: false },
                { command: "delete", path: "foo/foo-03/foobar.js", isDirectory: false },
                { command: "delete", path: "foo/foobar.js", isDirectory: false },
                { command: "new", path: "bar/bar-01/foobar-new.js", isDirectory: false },
                { command: "change", path: "foo/foo-02/foobar.js", isDirectory: false },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for rename, new, delete folders', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.rimrafSync(Path.join(root, "foo/foo-01"));
            Fs.rimrafSync(Path.join(root, "bar"));

            Fs.renameSync(Path.join(root, "foo"), Path.join(root, "bar-new") );

            Fs.mkdirSync(Path.join(root, "foo-new"));
            Fs.mkdirSync(Path.join(root, "foo-new/foo-01"));
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "delete", path: "bar", isDirectory: true },
                { command: "delete", path: "foo", isDirectory: true },
                { command: "new", path: "bar-new", isDirectory: true },
                { command: "new", path: "foo-new", isDirectory: true },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });
});
<commit_msg>make sure foobar exists<commit_after>var FireWatch = require('../index');
var Fs = require('fire-fs');
var Path = require('fire-path');

function reset () {
    Fs.rimrafSync("./test/foobar/");
    Fs.copySync("./test/test-data/", "./test/foobar");
}

function printResults ( results ) {
    console.log();
    console.log("    ---------------- results ----------------");
    results.forEach( function ( item ) {
        var text = "    %s: %s " + (item.isDirectory ? "[folder]" : "");
        console.log( text, item.command, item.path );
    });
}
function mapResults ( results ) {
    return results.map( function ( item ) {
        item.path = Path.join(root, item.path);
        return item;
    });
}

reset();
var root = Fs.realpathSync("./test/foobar/");

describe('FireWatch Simple Case', function () {
    it('should work for new file', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start(root, function () {
            Fs.writeFileSync(Path.join(root, "foo/foo-01/foobar-new.js"), "Hello World!");
            Fs.writeFileSync(Path.join(root, "foo/foobar-new.js"), "Hello World!");
        });
        watcher.stop( function () { done(); } );
        watcher.on("changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "new", path: "foo/foo-01/foobar-new.js", isDirectory: false },
                { command: "new", path: "foo/foobar-new.js", isDirectory: false },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for new folder', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.mkdirSync(Path.join(root, "foo/foo-01-new"));
            Fs.mkdirSync(Path.join(root, "foo-new"));
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "new", path: "foo-new", isDirectory: true },
                { command: "new", path: "foo/foo-01-new", isDirectory: true },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for delete file', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.rimrafSync(Path.join(root, "foo/foobar.js"));
            Fs.rimrafSync(Path.join(root, "foo/foo-01/foobar.js"));
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "delete", path: "foo/foo-01/foobar.js", isDirectory: false },
                { command: "delete", path: "foo/foobar.js", isDirectory: false },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for delete folder', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.rimrafSync(Path.join(root, "foo/foo-01"));
            Fs.rimrafSync(Path.join(root, "bar"));
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "delete", path: "bar", isDirectory: true },
                { command: "delete", path: "foo/foo-01", isDirectory: true },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for rename file', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.renameSync( Path.join(root, "foo/foobar.js"),
                           Path.join(root, "foo/foobar-rename.js") );

            Fs.renameSync( Path.join(root, "foo/foo-01/foobar.js"),
                           Path.join(root, "bar/bar-01/foobar-rename.js") );

            Fs.renameSync( Path.join(root, "foo/foo-02/foobar.js"),
                           Path.join(root, "bar/bar-02/foobar-rename.js") );

            Fs.renameSync( Path.join(root, "foo/foo-03/foobar.js"),
                           Path.join(root, "bar/bar-02/foobar-rename.js") );
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "delete", path: "foo/foo-01/foobar.js", isDirectory: false },
                { command: "delete", path: "foo/foo-02/foobar.js", isDirectory: false },
                { command: "delete", path: "foo/foo-03/foobar.js", isDirectory: false },
                { command: "delete", path: "foo/foobar.js", isDirectory: false },
                { command: "new", path: "bar/bar-01/foobar-rename.js", isDirectory: false },
                { command: "new", path: "bar/bar-02/foobar-rename.js", isDirectory: false },
                { command: "new", path: "foo/foobar-rename.js", isDirectory: false },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for rename folder', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.renameSync( Path.join(root, "foo/foo-01"),
                           Path.join(root, "bar/bar-04") );
            Fs.renameSync( Path.join(root, "foo/foo-02"),
                           Path.join(root, "bar/bar-04/bar-02") );
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "delete", path: "foo/foo-01", isDirectory: true },
                { command: "delete", path: "foo/foo-02", isDirectory: true },
                { command: "new", path: "bar/bar-04", isDirectory: true },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for editing file', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.writeFileSync(Path.join(root,"foo/foobar.js"), "Hello World!");
            Fs.writeFileSync(Path.join(root,"foo/foo-02/foobar.js"), "Hello World!");
            Fs.writeFileSync(Path.join(root,"bar/bar-01/foobar-new.js"), "Hello World!");
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "new", path: "bar/bar-01/foobar-new.js", isDirectory: false },
                { command: "change", path: "foo/foo-02/foobar.js", isDirectory: false },
                { command: "change", path: "foo/foobar.js", isDirectory: false },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });
});

describe('FireWatch Compound Case', function () {
    it('should work for rename, new, delete, editing files', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.writeFileSync(Path.join(root,"foo/foobar.js"), "Hello World!");
            Fs.rimrafSync(Path.join(root, "foo/foobar.js"));

            Fs.writeFileSync(Path.join(root,"foo/foo-02/foobar.js"), "Hello World!");
            Fs.writeFileSync(Path.join(root,"bar/bar-01/foobar-new.js"), "Hello World!");

            Fs.renameSync( Path.join(root, "foo/foo-03/foobar.js"),
                           Path.join(root, "bar/bar-03/foobar-rename.js") );

            Fs.rimrafSync(Path.join(root, "foo/foo-01/foobar.js"));
            Fs.rimrafSync(Path.join(root, "bar/bar-03/foobar-rename.js"));
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "delete", path: "foo/foo-01/foobar.js", isDirectory: false },
                { command: "delete", path: "foo/foo-03/foobar.js", isDirectory: false },
                { command: "delete", path: "foo/foobar.js", isDirectory: false },
                { command: "new", path: "bar/bar-01/foobar-new.js", isDirectory: false },
                { command: "change", path: "foo/foo-02/foobar.js", isDirectory: false },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });

    it('should work for rename, new, delete folders', function ( done ) {
        this.timeout(10000);
        reset();

        var watcher = FireWatch.start( root, function () {
            Fs.rimrafSync(Path.join(root, "foo/foo-01"));
            Fs.rimrafSync(Path.join(root, "bar"));

            Fs.renameSync(Path.join(root, "foo"), Path.join(root, "bar-new") );

            Fs.mkdirSync(Path.join(root, "foo-new"));
            Fs.mkdirSync(Path.join(root, "foo-new/foo-01"));
        });
        watcher.stop( function () { done(); } );
        watcher.on( "changed", function ( results ) {
            printResults(results);

            var expectResults = [
                { command: "delete", path: "bar", isDirectory: true },
                { command: "delete", path: "foo", isDirectory: true },
                { command: "new", path: "bar-new", isDirectory: true },
                { command: "new", path: "foo-new", isDirectory: true },
            ];
            expectResults = mapResults(expectResults);

            results.should.eql(expectResults);
        });
    });
});
<|endoftext|>


<commit_before>/* eslint-disable */

function loadMixpanel(e, a) {
  if (!a.__SV) {
    let b = window; try {
      var c,
        l,
        i,
        j = b.location,
        g = j.hash; c = function (a, b) { return (l = a.match(RegExp(`${b}=([^&]*)`))) ? l[1] : null; }; g && c(g, 'state') && (i = JSON.parse(decodeURIComponent(c(g, 'state'))), i.action === 'mpeditor' && (b.sessionStorage.setItem('_mpcehash', g), history.replaceState(i.desiredHash || '', e.title, j.pathname + j.search)));
    } catch (m) {} let k,
      h; window.mixpanel = a; a._i = []; a.init = function (b, c, f) {
        function e(b, a) {
          const c = a.split('.'); c.length == 2 && (b = b[c[0]], a = c[1]); b[a] = function () {
            b.push([a].concat(Array.prototype.slice.call(arguments,
  0)));
          };
        } let d = a; typeof f !== 'undefined' ? d = a[f] = [] : f = 'mixpanel'; d.people = d.people || []; d.toString = function (b) { let a = 'mixpanel'; f !== 'mixpanel' && (a += `.${f}`); b || (a += ' (stub)'); return a; }; d.people.toString = function () { return `${d.toString(1)}.people (stub)`; }; k = 'disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config reset people.set people.set_once people.increment people.append people.union people.track_charge people.clear_charges people.delete_user'.split(' ');
        for (h = 0; h < k.length; h++)e(d, k[h]); a._i.push([b, c, f]);
      }; a.__SV = 1.2; b = e.createElement('script'); b.type = 'text/javascript'; b.async = !0; b.src = typeof MIXPANEL_CUSTOM_LIB_URL !== 'undefined' ? MIXPANEL_CUSTOM_LIB_URL : e.location.protocol === 'file:' && '//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js'.match(/^\/\//) ? 'https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js' : '//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js'; c = e.getElementsByTagName('script')[0]; c.parentNode.insertBefore(b, c);
  }
}

export default function (document, window, env) {
  if (env === 'production') {
    loadMixpanel(document, window.mixpanel || []);
    window.mixpanel.init(process.env.MIXPANEL);
  } else {
    window.mixpanel = {
      track(ev, params) { console.log('MIXPANEL TRACK', ev, params); },
    };
  }
}

<commit_msg>Un-lint mixpanel<commit_after>/* eslint-disable */

function loadMixpanel(e, a) {
if(!a.__SV){var b=window;try{var c,l,i,j=b.location,g=j.hash;c=function(a,b){return(l=a.match(RegExp(b+"=([^&]*)")))?l[1]:null};g&&c(g,"state")&&(i=JSON.parse(decodeURIComponent(c(g,"state"))),"mpeditor"===i.action&&(b.sessionStorage.setItem("_mpcehash",g),history.replaceState(i.desiredHash||"",e.title,j.pathname+j.search)))}catch(m){}var k,h;window.mixpanel=a;a._i=[];a.init=function(b,c,f){function e(b,a){var c=a.split(".");2==c.length&&(b=b[c[0]],a=c[1]);b[a]=function(){b.push([a].concat(Array.prototype.slice.call(arguments,
0)))}}var d=a;"undefined"!==typeof f?d=a[f]=[]:f="mixpanel";d.people=d.people||[];d.toString=function(b){var a="mixpanel";"mixpanel"!==f&&(a+="."+f);b||(a+=" (stub)");return a};d.people.toString=function(){return d.toString(1)+".people (stub)"};k="disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config reset people.set people.set_once people.increment people.append people.union people.track_charge people.clear_charges people.delete_user".split(" ");
for(h=0;h<k.length;h++)e(d,k[h]);a._i.push([b,c,f])};a.__SV=1.2;b=e.createElement("script");b.type="text/javascript";b.async=!0;b.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?MIXPANEL_CUSTOM_LIB_URL:"file:"===e.location.protocol&&"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//)?"https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";c=e.getElementsByTagName("script")[0];c.parentNode.insertBefore(b,c)}
}

export default function (document, window, env) {
  if (env === 'production') {
    loadMixpanel(document, window.mixpanel || []);
    window.mixpanel.init(process.env.MIXPANEL);
  } else {
    window.mixpanel = {
      track(ev, params) { console.log('MIXPANEL TRACK', ev, params); },
    };
  }
}

<|endoftext|>


<commit_before>Ext.define('doweown.view.AvailView', {
    extend: 'Ext.DataView',
    xtype: 'availview',

    config: {
           title: 'Availability',
           store: 'BranchStore',
           /*onItemDisclosure: function( record, btn, index ) {
                                Ext.Msg.alert( record.get('collection.collectionname'), Ext.emptyFn);
            },*/
            itemTpl: '
 {repository.name} <tpl for="collection">
 {collectionname}<tpl for="items">
 <tpl switch="isavail"><tpl case="N" case="n">Not Available<tpl default>Available</tpl>:{stat}
 Call#: {call}
 {req.content}
</tpl> <tpl for="holdtag">
 {availkey} {availval.content}
</tpl>  <tpl for="online"> {content}
</tpl> </tpl>

'
     }

});
<commit_msg>fixed callnumber<commit_after>Ext.define('doweown.view.AvailView', {
    extend: 'Ext.DataView',
    xtype: 'availview',

    config: {
           title: 'Availability',
           store: 'BranchStore',
           /*onItemDisclosure: function( record, btn, index ) {
                                Ext.Msg.alert( record.get('collection.collectionname'), Ext.emptyFn);
            },*/
            itemTpl: '
 {repository.name} <tpl for="collection">
 {collectionname}
{callnumber}</tpl><tpl for="items">
 <tpl switch="isavail"><tpl case="N" case="n">Not Available<tpl default>Available</tpl>:{stat}
 Call#: {call}
 {req.content}
</tpl> <tpl for="holdtag">
 {availkey} {availval.content}
</tpl>  <tpl for="online"> {content}
</tpl> </tpl>

'
     }

});
<|endoftext|>


<commit_before>/*
This file is part of Archivematica.

Copyright 2010-2012 Artefactual Systems Inc. <http://artefactual.com>

Archivematica is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Archivematica is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Archivematica.  If not, see <http://www.gnu.org/licenses/>.
*/

$(function()
  {
    window.Sip = Sip.extend({
      methodUrl: {
        delete: '/ingest/uuid/delete/'
      }
    });

    window.SipCollection = Backbone.Collection.extend({

      model: Sip,

      url: '/ingest/status/',

      initialize: function()
        {

        },

      comparator: function(sip)
        {
          return -1 * sip.get('timestamp');
        }

    });

    window.SipView = BaseSipView.extend({

      template: _.template($('#sip-template').html()),

      initialize: function()
        {
          _.bindAll(this, 'render', 'update', 'updateIcon');
          this.model.view = this;
          this.model.bind('change:timestamp', this.update);
        },

      openPanel: function(event)
        {
          event.preventDefault();

          window.location = '/ingest/' + this.model.get('uuid') + '/';
        },

      remove: function(event)
        {
          event.preventDefault();
          event.stopPropagation();

          $(this.el).addClass('sip-removing');

          var self = this;

          $('
' +
              '
Are you sure you want to remove this SIP from the dashboard? Note that this does not delete the SIP or related entities.
' +
              '
Directory: ' + this.model.get('directory') + '
UUID: ' + this.model.get('uuid') + '
Status: ' + $(this.el).find('.sip-detail-icon-status > img').attr('title') + '
' +
            '
').dialog(
            {
              modal: true,
              resizable: false,
              draggable: false,
              title: 'Remove SIP',
              width: 480,
              close: function(event, ui)
                {
                  if (event.which !== undefined)
                  {
                    $(self.el).removeClass('sip-removing');
                  }
                },
              buttons: [
                  {
                    text: 'Confirm',
                    click: function() {

                      var $dialog = $(this);

                      self.model.destroy({
                        success: function (model, response)
                          {
                            $dialog.dialog('close');

                            setTimeout(function()
                              {
                                $(self.el).hide('blind', function()
                                  {
                                    $(this).remove();
                                  });
                              }, 250);
                          },
                        error: function(model, response)
                          {
                            $dialog.dialog('close');
                            $(self.el).removeClass('sip-removing');
                          }

                      });
                    }
                  },
                  {
                    text: 'Cancel',
                    click: function() {
                        $(this).dialog('close');
                        $(self.el).removeClass('sip-removing');
                      }
                  }]
            });
        },

       openMetadataEditor: function(event)
        {
          event.stopPropagation();
          event.preventDefault();

          var url = '/ingest/metadata/' + this.model.get('uuid') + '/';
          var self = this;

          var showDialog = function(data)
            {
              var dialog = $('

')
                .append(_.template($('#metadata-dialog').html(), data))
                .dialog({
                  title: 'Dublin Core metadata editor',
                  width: 610,
                  height: 480,
                  modal: true,
                  resizable: false,
                  buttons: [
                    {
                      text: 'Close',
                      click: function()
                        {
                          $(this).dialog('close');
                        }
                    },
                    {
                      text: 'Save',
                      click: function()
                        {
                          $.ajax({
                            context: this,
                            type: 'POST',
                            dataType: 'json',
                            data: $(this).find('form').serialize(),
                            success: function()
                              {
                                $(this).dialog('close');
                              },
                            error: function()
                              {
                                alert("Error.");
                              },
                            url: url});
                        }
                    }]
                });

              if (self.model.jobs.detect(function(job)
                {
                  return job.get('type') === 'Normalize submission documentation to preservation format';
                }))
              {
                dialog.find('input, select, textarea').prop('disabled', true).addClass('disabled');
                dialog.dialog('option', 'buttons', dialog.dialog('option', 'buttons').splice(0,1));
              }
            };

          $.ajax({
            type: 'GET',
            dataType: 'json',
            success: function(data)
              {
                showDialog(data);
              },
            url: url
          });

        }
    });

    window.JobView = BaseJobView.extend({

      className: 'job',

      events: {
        'click .btn_browse_job': 'browseJob',
        'click .btn_approve_job': 'approveJob',
        'click .btn_reject_job': 'rejectJob',
        'click .btn_show_tasks': 'showTasks',
        'click .btn_normalization_report': 'normalizationReport',
        'change select': 'action'
      },

      template: _.template($('#job-template').html()),

      render: function()
        {
          $(this.el).html(this.template(this.model.toJSON()));

          $(this.el).css(
            'background-color',
            this.getStatusColor(this.model.get('currentstep'))
          );

          // Micro-services requiring approval
          if (1 === this.model.get('status'))
          {
            this.$('.job-detail-actions')
              .append('Browse')
              .append('Approve')
              .append('Reject');
          }
          else
          {
            // ...
          }

          choices = this.model.get('choices');

          if (choices)
          {
            var $select = $('<select />').append('<option>Actions</option>')
              , numberOfChoices = Object.keys(choices).length;

            // use pop-up action selector for long choice lists
            if (numberOfChoices >= 10)
            {
              var statusObject = {};
              this.activateEnhancedActionSelect($select, statusObject);
            }

            for (var code in choices)
            {
              $select.append('<option value="' + code + '">- ' + choices[code] + '</option>');
            }

            this.$('.job-detail-actions').append($select);
          }

          if ('Approve normalization' == this.model.get('type'))
          {
            this.$('.job-detail-actions')
              .append('Report');
          }

          this.$('.job-detail-microservice > a').tooltip();

          this.$('.job-detail-actions > a').twipsy();

          return this;
        },

      action: function(event)
        {
          var $select = $(event.target);
          var value = $select.val();

          // Define function to execute
          var executeCommand = function(context)
            {
              $.ajax({
                context: this,
                data: { uuid: context.model.get('uuid'), choice: value },
                type: 'POST',
                success: function(data)
                  {
                    context.model.set({
                      'currentstep': 'Executing command(s)',
                      'status': 0
                    });

                    context.model.sip.view.updateIcon();
                  },
                url: '/mcp/execute/'
              });
            };

          // if ('Upload DIP' == this.model.get('type') && 13 == value)
          if ('- Upload DIP to Atom' == $select.find('option:selected').text())
          {
            var modal = $('#upload-dip-modal');
            var input = modal.find('input');
            var process = false;
            var url = '/ingest/' + this.model.sip.get('uuid') + '/upload/';
            var self = this;

            modal

              .one('show', function()
                {
                  var xhr = $.ajax(url, { type: 'GET' });
                  xhr
                    .done(function(data)
                      {
                        if (data.target)
                        {
                          input.filter(':text').val(data.target);
                          input.filter(':checkbox').prop('checked', data.intermediate);
                        }
                      });
                })

              .one('hidden', function()
                {
                  input.filter(':text').val('');
                  input.filter(':checkbox').prop('checked', false);
                  $select.val(0);
                  modal.find('a.primary, a.secondary').unbind('click');
                })

              .find('a.primary').bind('click', function(event)
                {
                  event.preventDefault();

                  if (input.filter(':text').val())
                  {
                    var xhr = $.ajax(url, { type: 'POST', data: {
                      'target': input.filter(':text').val(),
                      'intermediate': input.filter(':checkbox').is(':checked') }})

                      .done(function(data)
                        {
                          if (data.ready)
                          {
                            executeCommand(self);
                          }
                        })
                      .fail(function()
                        {
                          alert("Error.");
                          $select.val(0);
                        })
                      .always(function()
                        {
                          modal.modal('hide');
                        });
                  }
                })
              .end()

              .find('a.secondary').bind('click', function(event)
                {
                  event.preventDefault();
                  $select.val(0);
                  modal.modal('hide');
                })
              .end()

              .modal('show');

            return false;
          }

          executeCommand(this);
        },

      normalizationReport: function(event)
        {
          event.preventDefault();

          $.ajax({
            context: this,
            type: 'GET',
            dataType: 'html',
            success: function(data)
              {
                $('

')
                  .append('
' + $(data).find('thead').html() + $(data).find('tbody').html() + '
')
                  .dialog({
                    title: this.model.sip.get('directory') + ' &raquo ' + this.model.get('type') + ' &raquo Normalization report',
                    width: 860,
                    height: 640,
                    modal: true,
                    buttons: [
                      {
                        text: 'Close',
                        click: function() { $(this).dialog('close'); }
                      }]
                  })
                  .find('a.file-location')
                    .popover(
                      {
                        trigger: 'hover',
                        content: function()
                          {
                            return $(this).attr('data-location').replace(/%.*%/gi, '');
                          }
                      }).click(function(event) { event.preventDefault(); });
              },
            url: '/ingest/normalization-report/' + this.model.sip.get('uuid') + '/'
          });
        }

    });

    window.DirectoryBrowserView = BaseDirectoryBrowserView.extend({
      template: _.template($('#directory-browser-template').html())
    });

    window.AppView = BaseAppView.extend({
      el: $('#sip-container')
    });

    $.fn.tooltip = tooltipPlugin;
    window.onresize = optimizeWidth;
    window.onload = optimizeWidth;

    $(document).ready(function()
      {
        // Create modal
        $('#upload-dip-modal')
          .modal({
            backdrop: true,
            keyboard: true
          });
      });

  }
);
<commit_msg>Tweaked how certain normalization subjobs are displayed.<commit_after>/*
This file is part of Archivematica.

Copyright 2010-2012 Artefactual Systems Inc. <http://artefactual.com>

Archivematica is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Archivematica is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Archivematica.  If not, see <http://www.gnu.org/licenses/>.
*/

$(function()
  {
    window.Sip = Sip.extend({
      methodUrl: {
        delete: '/ingest/uuid/delete/'
      }
    });

    window.SipCollection = Backbone.Collection.extend({

      model: Sip,

      url: '/ingest/status/',

      initialize: function()
        {

        },

      comparator: function(sip)
        {
          return -1 * sip.get('timestamp');
        }

    });

    window.SipView = BaseSipView.extend({

      template: _.template($('#sip-template').html()),

      initialize: function()
        {
          _.bindAll(this, 'render', 'update', 'updateIcon');
          this.model.view = this;
          this.model.bind('change:timestamp', this.update);
        },

      openPanel: function(event)
        {
          event.preventDefault();

          window.location = '/ingest/' + this.model.get('uuid') + '/';
        },

      remove: function(event)
        {
          event.preventDefault();
          event.stopPropagation();

          $(this.el).addClass('sip-removing');

          var self = this;

          $('
' +
              '
Are you sure you want to remove this SIP from the dashboard? Note that this does not delete the SIP or related entities.
' +
              '
Directory: ' + this.model.get('directory') + '
UUID: ' + this.model.get('uuid') + '
Status: ' + $(this.el).find('.sip-detail-icon-status > img').attr('title') + '
' +
            '
').dialog(
            {
              modal: true,
              resizable: false,
              draggable: false,
              title: 'Remove SIP',
              width: 480,
              close: function(event, ui)
                {
                  if (event.which !== undefined)
                  {
                    $(self.el).removeClass('sip-removing');
                  }
                },
              buttons: [
                  {
                    text: 'Confirm',
                    click: function() {

                      var $dialog = $(this);

                      self.model.destroy({
                        success: function (model, response)
                          {
                            $dialog.dialog('close');

                            setTimeout(function()
                              {
                                $(self.el).hide('blind', function()
                                  {
                                    $(this).remove();
                                  });
                              }, 250);
                          },
                        error: function(model, response)
                          {
                            $dialog.dialog('close');
                            $(self.el).removeClass('sip-removing');
                          }

                      });
                    }
                  },
                  {
                    text: 'Cancel',
                    click: function() {
                        $(this).dialog('close');
                        $(self.el).removeClass('sip-removing');
                      }
                  }]
            });
        },

       openMetadataEditor: function(event)
        {
          event.stopPropagation();
          event.preventDefault();

          var url = '/ingest/metadata/' + this.model.get('uuid') + '/';
          var self = this;

          var showDialog = function(data)
            {
              var dialog = $('

')
                .append(_.template($('#metadata-dialog').html(), data))
                .dialog({
                  title: 'Dublin Core metadata editor',
                  width: 610,
                  height: 480,
                  modal: true,
                  resizable: false,
                  buttons: [
                    {
                      text: 'Close',
                      click: function()
                        {
                          $(this).dialog('close');
                        }
                    },
                    {
                      text: 'Save',
                      click: function()
                        {
                          $.ajax({
                            context: this,
                            type: 'POST',
                            dataType: 'json',
                            data: $(this).find('form').serialize(),
                            success: function()
                              {
                                $(this).dialog('close');
                              },
                            error: function()
                              {
                                alert("Error.");
                              },
                            url: url});
                        }
                    }]
                });

              if (self.model.jobs.detect(function(job)
                {
                  return job.get('type') === 'Normalize submission documentation to preservation format';
                }))
              {
                dialog.find('input, select, textarea').prop('disabled', true).addClass('disabled');
                dialog.dialog('option', 'buttons', dialog.dialog('option', 'buttons').splice(0,1));
              }
            };

          $.ajax({
            type: 'GET',
            dataType: 'json',
            success: function(data)
              {
                showDialog(data);
              },
            url: url
          });

        }
    });

    window.JobView = BaseJobView.extend({

      className: 'job',

      events: {
        'click .btn_browse_job': 'browseJob',
        'click .btn_approve_job': 'approveJob',
        'click .btn_reject_job': 'rejectJob',
        'click .btn_show_tasks': 'showTasks',
        'click .btn_normalization_report': 'normalizationReport',
        'change select': 'action'
      },

      template: _.template($('#job-template').html()),

      render: function()
        {
          var jobData = this.model.toJSON();

          if (
            jobData.type == 'Access normalization failed - copying'
            || jobData.type == 'Preservation normalization failed - copying'
          ) {
            jobData.currentstep = 'Failed';
          }

          $(this.el).html(this.template(jobData));

          $(this.el).css(
            'background-color',
            this.getStatusColor(jobData.currentstep)
          );

          // Micro-services requiring approval
          if (1 === this.model.get('status'))
          {
            this.$('.job-detail-actions')
              .append('Browse')
              .append('Approve')
              .append('Reject');
          }
          else
          {
            // ...
          }

          choices = this.model.get('choices');

          if (choices)
          {
            var $select = $('<select />').append('<option>Actions</option>')
              , numberOfChoices = Object.keys(choices).length;

            // use pop-up action selector for long choice lists
            if (numberOfChoices >= 10)
            {
              var statusObject = {};
              this.activateEnhancedActionSelect($select, statusObject);
            }

            for (var code in choices)
            {
              $select.append('<option value="' + code + '">- ' + choices[code] + '</option>');
            }

            this.$('.job-detail-actions').append($select);
          }

          if ('Approve normalization' == this.model.get('type'))
          {
            this.$('.job-detail-actions')
              .append('Report');
          }

          this.$('.job-detail-microservice > a').tooltip();

          this.$('.job-detail-actions > a').twipsy();

          return this;
        },

      action: function(event)
        {
          var $select = $(event.target);
          var value = $select.val();

          // Define function to execute
          var executeCommand = function(context)
            {
              $.ajax({
                context: this,
                data: { uuid: context.model.get('uuid'), choice: value },
                type: 'POST',
                success: function(data)
                  {
                    context.model.set({
                      'currentstep': 'Executing command(s)',
                      'status': 0
                    });

                    context.model.sip.view.updateIcon();
                  },
                url: '/mcp/execute/'
              });
            };

          // if ('Upload DIP' == this.model.get('type') && 13 == value)
          if ('- Upload DIP to Atom' == $select.find('option:selected').text())
          {
            var modal = $('#upload-dip-modal');
            var input = modal.find('input');
            var process = false;
            var url = '/ingest/' + this.model.sip.get('uuid') + '/upload/';
            var self = this;

            modal

              .one('show', function()
                {
                  var xhr = $.ajax(url, { type: 'GET' });
                  xhr
                    .done(function(data)
                      {
                        if (data.target)
                        {
                          input.filter(':text').val(data.target);
                          input.filter(':checkbox').prop('checked', data.intermediate);
                        }
                      });
                })

              .one('hidden', function()
                {
                  input.filter(':text').val('');
                  input.filter(':checkbox').prop('checked', false);
                  $select.val(0);
                  modal.find('a.primary, a.secondary').unbind('click');
                })

              .find('a.primary').bind('click', function(event)
                {
                  event.preventDefault();

                  if (input.filter(':text').val())
                  {
                    var xhr = $.ajax(url, { type: 'POST', data: {
                      'target': input.filter(':text').val(),
                      'intermediate': input.filter(':checkbox').is(':checked') }})

                      .done(function(data)
                        {
                          if (data.ready)
                          {
                            executeCommand(self);
                          }
                        })
                      .fail(function()
                        {
                          alert("Error.");
                          $select.val(0);
                        })
                      .always(function()
                        {
                          modal.modal('hide');
                        });
                  }
                })
              .end()

              .find('a.secondary').bind('click', function(event)
                {
                  event.preventDefault();
                  $select.val(0);
                  modal.modal('hide');
                })
              .end()

              .modal('show');

            return false;
          }

          executeCommand(this);
        },

      normalizationReport: function(event)
        {
          event.preventDefault();

          $.ajax({
            context: this,
            type: 'GET',
            dataType: 'html',
            success: function(data)
              {
                $('

')
                  .append('
' + $(data).find('thead').html() + $(data).find('tbody').html() + '
')
                  .dialog({
                    title: this.model.sip.get('directory') + ' &raquo ' + this.model.get('type') + ' &raquo Normalization report',
                    width: 860,
                    height: 640,
                    modal: true,
                    buttons: [
                      {
                        text: 'Close',
                        click: function() { $(this).dialog('close'); }
                      }]
                  })
                  .find('a.file-location')
                    .popover(
                      {
                        trigger: 'hover',
                        content: function()
                          {
                            return $(this).attr('data-location').replace(/%.*%/gi, '');
                          }
                      }).click(function(event) { event.preventDefault(); });
              },
            url: '/ingest/normalization-report/' + this.model.sip.get('uuid') + '/'
          });
        }

    });

    window.DirectoryBrowserView = BaseDirectoryBrowserView.extend({
      template: _.template($('#directory-browser-template').html())
    });

    window.AppView = BaseAppView.extend({
      el: $('#sip-container')
    });

    $.fn.tooltip = tooltipPlugin;
    window.onresize = optimizeWidth;
    window.onload = optimizeWidth;

    $(document).ready(function()
      {
        // Create modal
        $('#upload-dip-modal')
          .modal({
            backdrop: true,
            keyboard: true
          });
      });

  }
);
<|endoftext|>


<commit_before>import * as I from "infestines"
import * as R from "ramda"

export const lazy = ty2ty => {
  let memo = x => {
    memo = ty2ty(rec)
    return memo(x)
  }
  const rec = x => memo(x)
  return rec
}

export const any = x => x

export const and = R.pipe

export const or = (...ps) => x => {
  const es = [], n = ps.length
  for (let i=0; i<n; ++i) {
    try {
      return ps[i](x)
    } catch (e) {
      es.push([ps[i], e])
    }
  }
  throw new Error(`or(${ps}): ${x}`)
}

export const fromPredicate = p => x => {
  if (p(x))
    return x
  throw new Error(`fromPredicate(${p}): ${x}`)
}

const type = t => fromPredicate(x => typeof x === t)
const instance = c => fromPredicate(x => x instanceof c)

const isntFreezable = x =>
  x === null
  || typeof x !== "object"
  || x instanceof Int8Array

const isFrozen = x =>
  isntFreezable(x)
  || Object.isFrozen(x)

const isDeepFrozen = x =>
  isntFreezable(x)
  || Object.isFrozen(x)
     && !Object.getOwnPropertyNames(x).find(x => !isDeepFrozen(x))

export const frozen = fromPredicate(isFrozen)

export const deepFrozen = fromPredicate(isDeepFrozen)

export const deepFreeze = x => isFrozen(x) ? x
  : (Object.getOwnPropertyNames(x).forEach(k => deepFreeze(x[k])),
     Object.freeze(x))

export const integer = fromPredicate(Number.isInteger)
export const nonNegative = and(integer, fromPredicate(x => 0 <= x))

export const boolean = type("boolean")
export const number = type("number")
export const string = type("string")
export const undef = fromPredicate(x => x === undefined)
export const def = fromPredicate(x => x !== undefined)

export const array = ty => and(instance(Array), R.map(ty))

export const arity = n => fromPredicate(x => x.length === n)

export const props = R.map

export const object = template => object => {
  const result = {}
  if (!I.isObject ||
      !I.hasKeysOfU(template, object) ||
      !I.hasKeysOfU(object, template))
    throw new Error(`object(${template}): ${object}`)
  for (const k in template)
    result[k] = template[k](object[k])
  return result
}

export const fn = (argTys, resultTy) => fn => {
  if (typeof fn !== "function" || argTys.length < fn.length)
    throw new Error(`fn(${argTys}, ${resultTy}): ${fn}`)
  return R.curryN(argTys.length, function (...argIns) {
    if (argTys.length !== argIns.length)
      throw new Error(`fn(${argTys}, ${resultTy}): got ${argIns.length} args`)
    const n=argIns.length, args=Array(n)
    for (let i=0; i<n; ++i)
      args[i] = argTys[i](argIns[i])
    return resultTy(fn.apply(this, args))
  })
}

export const fnVar = (argsTy, resultTy) => fn => {
  if (typeof fn !== "function")
    throw new Error(`fnVar(${argsTy}, ${resultTy}): ${fn}`)
  return function (...argIns) {
    const n=argIns.length, args=Array(n)
    for (let i=0; i<n; ++i)
      args[i] = argsTy(argIns[i])
    return resultTy(fn.apply(this, args))
  }
}
<commit_msg>Only consider plain arrays and objects freezable<commit_after>import * as I from "infestines"
import * as R from "ramda"

export const lazy = ty2ty => {
  let memo = x => {
    memo = ty2ty(rec)
    return memo(x)
  }
  const rec = x => memo(x)
  return rec
}

export const any = x => x

export const and = R.pipe

export const or = (...ps) => x => {
  const es = [], n = ps.length
  for (let i=0; i<n; ++i) {
    try {
      return ps[i](x)
    } catch (e) {
      es.push([ps[i], e])
    }
  }
  throw new Error(`or(${ps}): ${x}`)
}

export const fromPredicate = p => x => {
  if (p(x))
    return x
  throw new Error(`fromPredicate(${p}): ${x}`)
}

const type = t => fromPredicate(x => typeof x === t)
const instance = c => fromPredicate(x => x instanceof c)

const isFreezable = x => I.isArray(x) || I.isObject(x)
const isFrozen = x => !isFreezable(x) || Object.isFrozen(x)
const isDeepFrozen = x =>
  !isFreezable(x)
  || Object.isFrozen(x)
     && !Object.getOwnPropertyNames(x).find(x => !isDeepFrozen(x))

export const frozen = fromPredicate(isFrozen)

export const deepFrozen = fromPredicate(isDeepFrozen)

export const deepFreeze = x => isFrozen(x) ? x
  : (Object.getOwnPropertyNames(x).forEach(k => deepFreeze(x[k])),
     Object.freeze(x))

export const integer = fromPredicate(Number.isInteger)
export const nonNegative = and(integer, fromPredicate(x => 0 <= x))

export const boolean = type("boolean")
export const number = type("number")
export const string = type("string")
export const undef = fromPredicate(x => x === undefined)
export const def = fromPredicate(x => x !== undefined)

export const array = ty => and(instance(Array), R.map(ty))

export const arity = n => fromPredicate(x => x.length === n)

export const props = R.map

export const object = template => object => {
  const result = {}
  if (!I.isObject ||
      !I.hasKeysOfU(template, object) ||
      !I.hasKeysOfU(object, template))
    throw new Error(`object(${template}): ${object}`)
  for (const k in template)
    result[k] = template[k](object[k])
  return result
}

export const fn = (argTys, resultTy) => fn => {
  if (typeof fn !== "function" || argTys.length < fn.length)
    throw new Error(`fn(${argTys}, ${resultTy}): ${fn}`)
  return R.curryN(argTys.length, function (...argIns) {
    if (argTys.length !== argIns.length)
      throw new Error(`fn(${argTys}, ${resultTy}): got ${argIns.length} args`)
    const n=argIns.length, args=Array(n)
    for (let i=0; i<n; ++i)
      args[i] = argTys[i](argIns[i])
    return resultTy(fn.apply(this, args))
  })
}

export const fnVar = (argsTy, resultTy) => fn => {
  if (typeof fn !== "function")
    throw new Error(`fnVar(${argsTy}, ${resultTy}): ${fn}`)
  return function (...argIns) {
    const n=argIns.length, args=Array(n)
    for (let i=0; i<n; ++i)
      args[i] = argsTy(argIns[i])
    return resultTy(fn.apply(this, args))
  }
}
<|endoftext|>