<commit_before>/**
 * @license
 * Copyright Google Inc. All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */

// Tun on full stack traces in errors to help debugging
Error.stackTraceLimit = Infinity;

jasmine.DEFAULT_TIMEOUT_INTERVAL = 100;

// Cancel Karma's synchronous start,
// we will call `__karma__.start()` later, once all the specs are loaded.
__karma__.loaded = function() {};

System.config({
  baseURL: '/base',
  defaultJSExtensions: true,
  map: {
    'benchpress/*': 'dist/js/dev/es5/benchpress/*.js',
    '@angular': 'dist/all/@angular',
    'rxjs': 'node_modules/rxjs',
    'parse5': 'dist/all/empty.js',
    '@angular/platform-server/src/parse5_adapter': 'dist/all/empty.js',
    'angular2/*': 'dist/all/angular2/*.js',
    'angular2/src/alt_router/router_testing_providers':
        'dist/all/angular2/src/alt_router/router_testing_providers.js'
  },
  packages: {
    '@angular/core/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/core': {main: 'index.js', defaultExtension: 'js'},
    '@angular/compiler/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/compiler': {main: 'index.js', defaultExtension: 'js'},
    '@angular/common/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/common': {main: 'index.js', defaultExtension: 'js'},
    '@angular/forms': {main: 'index.js', defaultExtension: 'js'},
    // remove after all tests imports are fixed
    '@angular/facade': {main: 'index.js', defaultExtension: 'js'},
    '@angular/router/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/router': {main: 'index.js', defaultExtension: 'js'},
    '@angular/http/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/http': {main: 'index.js', defaultExtension: 'js'},
    '@angular/upgrade': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-browser/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-browser-dynamic/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-server/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-server': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-webworker': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-webworker-dynamic': {main: 'index.js', defaultExtension: 'js'},
  }
});

// Set up the test injector, then import all the specs, execute their `main()`
// method and kick off Karma (Jasmine).
System.import('@angular/core/testing')
    .then(function(coreTesting) {
      return System.import('@angular/platform-browser-dynamic/testing')
          .then(function(browserTesting) {
            coreTesting.TestBed.initTestEnvironment(
                browserTesting.BrowserDynamicTestingModule,
                browserTesting.platformBrowserDynamicTesting());
          });
    })
    .then(function() {
      return Promise.all(Object
                             .keys(window.__karma__.files)  // All files served by Karma.
                             .filter(onlySpecFiles)
                             .map(window.file2moduleName)  // Normalize paths to module names.
                             .map(function(path) {
                               return System.import(path).then(function(module) {
                                 if (module.hasOwnProperty('main')) {
                                   module.main();
                                 } else {
                                   throw new Error(
                                       'Module ' + path + ' does not implement main() method.');
                                 }
                               });
                             }));
    })
    .then(function() { __karma__.start(); }, function(error) { console.error(error); });

function onlySpecFiles(path) {
  return /_spec\.js$/.test(path);
}
<commit_msg>test: add missing change to test-main.js<commit_after>/**
 * @license
 * Copyright Google Inc. All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */

// Tun on full stack traces in errors to help debugging
Error.stackTraceLimit = Infinity;

jasmine.DEFAULT_TIMEOUT_INTERVAL = 100;

// Cancel Karma's synchronous start,
// we will call `__karma__.start()` later, once all the specs are loaded.
__karma__.loaded = function() {};

System.config({
  baseURL: '/base',
  defaultJSExtensions: true,
  map: {
    'benchpress/*': 'dist/js/dev/es5/benchpress/*.js',
    '@angular': 'dist/all/@angular',
    'rxjs': 'node_modules/rxjs',
    'parse5': 'dist/all/empty.js',
    'url': 'dist/all/empty.js',
    '@angular/platform-server/src/parse5_adapter': 'dist/all/empty.js',
    'angular2/*': 'dist/all/angular2/*.js',
    'angular2/src/alt_router/router_testing_providers':
        'dist/all/angular2/src/alt_router/router_testing_providers.js'
  },
  packages: {
    '@angular/core/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/core': {main: 'index.js', defaultExtension: 'js'},
    '@angular/compiler/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/compiler': {main: 'index.js', defaultExtension: 'js'},
    '@angular/common/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/common': {main: 'index.js', defaultExtension: 'js'},
    '@angular/forms': {main: 'index.js', defaultExtension: 'js'},
    // remove after all tests imports are fixed
    '@angular/facade': {main: 'index.js', defaultExtension: 'js'},
    '@angular/router/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/router': {main: 'index.js', defaultExtension: 'js'},
    '@angular/http/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/http': {main: 'index.js', defaultExtension: 'js'},
    '@angular/upgrade': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-browser/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-browser-dynamic/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-server/testing': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-server': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-webworker': {main: 'index.js', defaultExtension: 'js'},
    '@angular/platform-webworker-dynamic': {main: 'index.js', defaultExtension: 'js'},
  }
});

// Set up the test injector, then import all the specs, execute their `main()`
// method and kick off Karma (Jasmine).
System.import('@angular/core/testing')
    .then(function(coreTesting) {
      return System.import('@angular/platform-browser-dynamic/testing')
          .then(function(browserTesting) {
            coreTesting.TestBed.initTestEnvironment(
                browserTesting.BrowserDynamicTestingModule,
                browserTesting.platformBrowserDynamicTesting());
          });
    })
    .then(function() {
      return Promise.all(Object
                             .keys(window.__karma__.files)  // All files served by Karma.
                             .filter(onlySpecFiles)
                             .map(window.file2moduleName)  // Normalize paths to module names.
                             .map(function(path) {
                               return System.import(path).then(function(module) {
                                 if (module.hasOwnProperty('main')) {
                                   module.main();
                                 } else {
                                   throw new Error(
                                       'Module ' + path + ' does not implement main() method.');
                                 }
                               });
                             }));
    })
    .then(function() { __karma__.start(); }, function(error) { console.error(error); });

function onlySpecFiles(path) {
  return /_spec\.js$/.test(path);
}
<|endoftext|>


<commit_before>'use strict';
let extractResponse = module.exports = function (response, specExtract) {
  if (typeof specExtract === 'undefined') {
    return response;
  }

  let result;
  if (isArray(response)) {
    result = extractFromArray(response, specExtract);
  } else {
    result = extractFromObject(response, specExtract);
  }

  return result;
};

function isArray (a) {
  return (!!a) && (a.constructor === Array);
}

function isObject (a) {
  return (!!a) && (a.constructor === Object);
}

function isNumeric (n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

function getField (response, field) {
  let fields = field.split('.');

  return getSplitFields(response, fields);
}

function getSplitFields (response, fieldsArray) {
  let result = isArray(response) && (!isNumeric(fieldsArray[0]))
    ? response.map((object) => object[fieldsArray[0]])
    : response[fieldsArray[0]];

  fieldsArray.shift();
  if (fieldsArray.length === 0) {
    return result;
  }
  return getSplitFields(result, fieldsArray);
}

function extractFromObject (response, specExtract) {
  if (!isArray(specExtract) && !isObject(specExtract)) {
    return getField(response, specExtract);
  }
  let result = isArray(specExtract) ? [] : {};
  for (let key in specExtract) {
    result[key] = extractFromObject(response, specExtract[key]);

  }
  return result;
}

function extractFromArray (response, specExtract) {
  return response.map((object) => extractFromObject(object, specExtract));
}
<commit_msg>added description for extractResponse<commit_after>'use strict';
/**
 * [extractResponse description]
 * @param  {object, array} response    [A parsed JSON response from an API]
 * @param  {string, array, object} specExtract [extract field specified in the API spec]
 * @return {string, array, object}             [The formatted fields from the response]
 */
let extractResponse = module.exports = function (response, specExtract) {
  if (typeof specExtract === 'undefined') {
    return response;
  }

  let result;
  if (isArray(response)) {
    result = extractFromArray(response, specExtract);
  } else {
    result = extractFromObject(response, specExtract);
  }

  return result;
};

function isArray (a) {
  return (!!a) && (a.constructor === Array);
}

function isObject (a) {
  return (!!a) && (a.constructor === Object);
}

function isNumeric (n) {
  return !isNaN(parseFloat(n)) && isFinite(n);
}

function getField (response, field) {
  let fields = field.split('.');

  return getSplitFields(response, fields);
}

function getSplitFields (response, fieldsArray) {
  let result = isArray(response) && (!isNumeric(fieldsArray[0]))
    ? response.map((object) => object[fieldsArray[0]])
    : response[fieldsArray[0]];

  fieldsArray.shift();
  if (fieldsArray.length === 0) {
    return result;
  }
  return getSplitFields(result, fieldsArray);
}

function extractFromObject (response, specExtract) {
  if (!isArray(specExtract) && !isObject(specExtract)) {
    return getField(response, specExtract);
  }
  let result = isArray(specExtract) ? [] : {};
  for (let key in specExtract) {
    result[key] = extractFromObject(response, specExtract[key]);

  }
  return result;
}

function extractFromArray (response, specExtract) {
  return response.map((object) => extractFromObject(object, specExtract));
}
<|endoftext|>


<commit_before>

module.exports = {
	setFilter : function(query) {
		let filter = {};

        // 기간 필터
        let dateRange = {};
        if (query.startRange != undefined) {
            //dateRange.start = query.startRange
            let temp_date = new Date(Number(query.startRange)).toISOString().split('T');
            dateRange.start = temp_date[0]+" "+temp_date[1].split('.')[0];
        }
        if (query.endRange != undefined) {
            //dateRange.end = query.endRange
            let temp_date = new Date(Number(query.endRange)).toISOString().split('T');
            dateRange.end = temp_date[0]+" "+temp_date[1].split('.')[0];
        }
        if (dateRange.start != undefined && dateRange.end != undefined) {
            filter.dateRange = dateRange;
        }

        // 사용량 필터
        let usageRange = {};
        if (query.startUsage != undefined) {
            usageRange.start = query.startUsage;
        }
        if (query.endUsage != undefined) {
            usageRange.end = query.endUsage;
        }
        if (usageRange.start != undefined && usageRange.end != undefined) {
            filter.usageRange = usageRange;
        }

        // 지역, 기기, os, Activity 필터
        if (query.location != undefined)
            filter.location = query.location.split(',');
        if (query.device != undefined)
            filter.device = query.device.split(',');
        if (query.os != undefined)
            filter.os = query.os.split(',');
        if (query.activity != undefined)
            filter.activity_name = query.activity.split(',');

        if (query.nlocation != undefined) {
        	filter.nlocation = query.nlocation.split(',');
        	filter.location = undefined;
        }
        if (query.ndevice != undefined) {
        	filter.ndevice = query.ndevice.split(',');
        	filter.device = undefined;
        }
        if (query.nos != undefined) {
        	filter.nos = query.nos.split(',');
        	filter.os = undefined;
        }
        if (query.nactivity != undefined) {
        	filter.nactivity_name = query.nactivity.split(',');
        	filter.activity_name = undefined;
        }

        return filter;
	}
}<commit_msg>*add none string filter<commit_after>

module.exports = {
	setFilter : function(query) {
		let filter = {};

        // 기간 필터
        let dateRange = {};
        if (query.startRange != undefined) {
            //dateRange.start = query.startRange
            let temp_date = new Date(Number(query.startRange)).toISOString().split('T');
            dateRange.start = temp_date[0]+" "+temp_date[1].split('.')[0];
        }
        if (query.endRange != undefined) {
            //dateRange.end = query.endRange
            let temp_date = new Date(Number(query.endRange)).toISOString().split('T');
            dateRange.end = temp_date[0]+" "+temp_date[1].split('.')[0];
        }
        if (dateRange.start != undefined && dateRange.end != undefined) {
            filter.dateRange = dateRange;
        }

        // 사용량 필터
        let usageRange = {};
        if (query.startUsage != undefined) {
            usageRange.start = query.startUsage;
        }
        if (query.endUsage != undefined) {
            usageRange.end = query.endUsage;
        }
        if (usageRange.start != undefined && usageRange.end != undefined) {
            filter.usageRange = usageRange;
        }

        // 지역, 기기, os, Activity 필터
        if (query.location != undefined && query.location != '')
            filter.location = query.location.split(',');
        if (query.device != undefined && query.device != '')
            filter.device = query.device.split(',');
        if (query.os != undefined && query.os != '')
            filter.os = query.os.split(',');
        if (query.activity != undefined && query.activity != '')
            filter.activity_name = query.activity.split(',');

        if (query.nlocation != undefined && query.nlocation != '') {
        	filter.nlocation = query.nlocation.split(',');
        	filter.location = undefined;
        }
        if (query.ndevice != undefined && query.ndevice != '') {
        	filter.ndevice = query.ndevice.split(',');
        	filter.device = undefined;
        }
        if (query.nos != undefined && query.nos != '') {
        	filter.nos = query.nos.split(',');
        	filter.os = undefined;
        }
        if (query.nactivity != undefined && query.nactivity != '') {
        	filter.nactivity_name = query.nactivity.split(',');
        	filter.activity_name = undefined;
        }

        return filter;
	}
}<|endoftext|>


<commit_before>//don't forget .exec() returns a promise
// { __v: 0} is a mongoose thing and if you don't put this in, it returns the json with this.
//handling of route happens in here.
'use strict';

var Image = require('../models/image');
var awsUpload = require('../lib/aws-upload');
var fileUpload = require('../lib/file-upload');
var User = require('../controllers/auth.js');

var index = function index(req, res, next) {

    Image.find({}, {__v: 0}).exec().then(function(images) {
    res.json(images);
  }).catch(function(error) {
    next(error);
  });
};

var create = function create(req, res, next) {
  awsUpload(req.file.buffer, {path: '/' + req.user.userName, ownerId: req.user._id, name: req.body.name}).then(function(data){
    res.json(data);
  }).catch(function(error) {
    next(error);
  });
};

var destroy = function destroy(req, res, next){
  var id = req.get("id");
  Image.findByIdAndRemove({ "_id": id }, function (err, image) {
    console.log("deleting single image");
      if (err) {
        return next(err);
    } else {
        res.json(image);
      }
  });

  // Image.findById(req.image._id).exec().then(function(image){
  //   // res.remove(image)
  //   return image.remove();
  // }).catch(function(error) {
  //   next(error);
  // };
};

// var show = function show(req, res, next) {
//   Image.find()
// };

module.exports = {
  index,
  create,
  destroy
};

<commit_msg>Fixes merge conflict<commit_after>//don't forget .exec() returns a promise
// { __v: 0} is a mongoose thing and if you don't put this in, it returns the json with this.
//handling of route happens in here.
'use strict';

var Image = require('../models/image');
var awsUpload = require('../lib/aws-upload');
var fileUpload = require('../lib/file-upload');
var User = require('../controllers/auth.js');

var index = function index(req, res, next) {

    Image.find({}, {__v: 0}).exec().then(function(images) {
    res.json(images);
  }).catch(function(error) {
    next(error);
  });
};

var create = function create(req, res, next) {
  awsUpload(req.file.buffer, {path: '/' + req.user.userName, ownerId: req.user._id, name: req.body.name}).then(function(data){
    res.json(data);
  }).catch(function(error) {
    next(error);
  });
};

var destroy = function destroy(req, res, next){
  var id = req.get("id");
  Image.remove({ "id": id }, function (err, image) {
    console.log("deleting single image");
      if (err) {
        return next(err);
    } else {
        res.json(image);
      }
  });

  // Image.findById(req.image._id).exec().then(function(image){
  //   // res.remove(image)
  //   return image.remove();
  // }).catch(function(error) {
  //   next(error);
  // };
};

// var show = function show(req, res, next) {
//   Image.find()
// };

module.exports = {
  index,
  create,
  destroy
};

<|endoftext|>


<commit_before>/*
Copyright (c) 2011, Chris Umbel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

var PorterStemmer = require('../stemmers/porter_stemmer'),
util = require('util'),
Classifier = require('./classifier'),
ApparatusBayesClassifier = require('apparatus').BayesClassifier;

var BayesClassifier = function(stemmer) {
    Classifier.call(this, new ApparatusBayesClassifier(), stemmer);
};

util.inherits(BayesClassifier, Classifier);

function restore(classifier, stemmer) {
    classifier = Classifier.restore(classifier);
    classifier.__proto__ = BayesClassifier.prototype;
    classifier.classifier = ApparatusBayesClassifier.restore(classifier.classifier);

    return classifier;
}

function load(filename, stemmer, callback) {
    Classifier.load(filename, function(err, classifier) {
        callback(err, restore(classifier));
    });
}

BayesClassifier.restore = restore;
BayesClassifier.load = load;

module.exports = BayesClassifier;
<commit_msg>Fix stemmer being passed properly<commit_after>/*
Copyright (c) 2011, Chris Umbel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

var PorterStemmer = require('../stemmers/porter_stemmer'),
util = require('util'),
Classifier = require('./classifier'),
ApparatusBayesClassifier = require('apparatus').BayesClassifier;

var BayesClassifier = function(stemmer) {
    Classifier.call(this, new ApparatusBayesClassifier(), stemmer);
};

util.inherits(BayesClassifier, Classifier);

function restore(classifier, stemmer) {
    classifier = Classifier.restore(classifier, stemmer);
    classifier.__proto__ = BayesClassifier.prototype;
    classifier.classifier = ApparatusBayesClassifier.restore(classifier.classifier);

    return classifier;
}

function load(filename, stemmer, callback) {
    Classifier.load(filename, function(err, classifier) {
        callback(err, restore(classifier, stemmer));
    });
}

BayesClassifier.restore = restore;
BayesClassifier.load = load;

module.exports = BayesClassifier;
<|endoftext|>


<commit_before>var mongoose = require('mongoose');
var keys     = require('keys');

var mongo_url;
if (process.env.NODE_ENV){
  mongo_url = 'mongodb://' + keys.mongo_user + ':' + 'keys.mongo_password' + "@SOMEURL:PORT/livebots"
} else {
  mongo_url = 'mongodb://localhost/livebots_dev';
}

require('./models/bots');
require('./models/commands');

module.exports = function() {
  console.log('CONNECTING TO MONGO');
  mongoose.connect(mongo_url);
  var db = mongoose.connection;

  db.on('error', console.error.bind(console, 'connection error:'));
  db.once('open', function (){
    console.log('Successfuly connected to mongoDB');
  });
};<commit_msg>test troupe<commit_after>var mongoose = require('mongoose');
var keys     = require('keys');

var mongo_url;
if (process.env.NODE_ENV){
  mongo_url = 'mongodb://' + keys.mongo_user + ':' + 'keys.mongo_password' + "@SOMEURL:PORT/livebots"
} else {
  mongo_url = 'mongodb://localhost/livebots_dev';
}

require('./models/bots');
require('./models/commands');

module.exports = function() {
  console.log('CONNECTING TO MONGO');
  mongoose.connect(mongo_url);
  var db = mongoose.connection;

  db.on('error', console.error.bind(console, 'connection error:'));
  db.once('open', function (){
    console.log('Successfuly connected to mongoDB');
  });
};<|endoftext|>


<commit_before>"use strict";

var models = require('../models');
var assert = require('assert');

var controller = {
  // GET /levels
  index: function(req, res) {
    models.Level.findAll().then(function(levels) {
      res.format({
        html: function() {
          res.render('levels/index', {
            title:  'Levels',
            levels: levels
          });
        },
        json: function() {
          res.send(levels);
        }
      });
    });
  },

  // POST /levels
  create: function(req, res) {
    models.Level
      .buildFromUrl(req.body.url, req)
      .save()
      .then(function(level) {
        res.send(level);
      })
      .catch(function(err) {
        res.status(422);
        res.send(err);
      });
  },

  // DELETE /levels/:id
  delete: function(req, res) {
    assert.equal(req.headers['authorization'], process.env.API_KEY, 'wrong API key');
    assert.ok(req.params.id, 'ID must be set');
    models.Level
      .find(req.params.id)
      .then(function(level) {
        level.destroy().then(function() {
          res.send({success: true});
        });
      });
  }
};

module.exports = controller;
<commit_msg>Catch for bad DELETE ID<commit_after>"use strict";

var models = require('../models');
var assert = require('assert');

var controller = {
  // GET /levels
  index: function(req, res) {
    models.Level.findAll().then(function(levels) {
      res.format({
        html: function() {
          res.render('levels/index', {
            title:  'Levels',
            levels: levels
          });
        },
        json: function() {
          res.send(levels);
        }
      });
    });
  },

  // POST /levels
  create: function(req, res) {
    models.Level
      .buildFromUrl(req.body.url, req)
      .save()
      .then(function(level) {
        res.send(level);
      })
      .catch(function(err) {
        res.status(422);
        res.send(err);
      });
  },

  // DELETE /levels/:id
  delete: function(req, res) {
    assert.equal(req.headers['authorization'], process.env.API_KEY, 'wrong API key');
    assert.ok(req.params.id, 'ID must be set');
    models.Level
      .find(req.params.id)
      .then(function(level) {
        level.destroy().then(function() {
          res.send({success: true});
        });
      })
      .catch(function(err) {
        res.send(err);
      });
  }
};

module.exports = controller;
<|endoftext|>


<commit_before>'use strict';

class DropdownList {
  constructor(element) {
    this.element = element;
    this.dropdownCollapseLabel = '.dropdown-list__item--collapse > .dropdown-list__label';
    this.dropdownItem = [...this.element.querySelectorAll(this.dropdownCollapseLabel)];
    this.contentClass = 'dropdown-list__content';
    this.mq = '(min-width: 768px)';
    this.mqClass = 'dropdown-list--is-open@screen-m';
    this.dropdownMediumOpen = this.element.classList.contains(this.mqClass);
    this.init();
  }

  setAriaAttributes(label, content, expanded) {
    if (expanded) {
      label.setAttribute('aria-expanded', 'false');
      content.setAttribute('aria-hidden', 'true');
    }
    else {
      label.setAttribute('aria-expanded', 'true');
      content.setAttribute('aria-hidden', 'false');
    }
  }

  removeAriaAttributes(label, content) {
    label.removeAttribute('aria-expanded');
    content.setAttribute('aria-hidden', 'false');
    label.disabled = true;
  }

  isMediumOpen(dropdownBlock) {
    return (dropdownBlock.classList.contains('dropdown-list--is-open@screen-m')) && window.matchMedia(this.mq).matches;
  }

  resetMqMediumOpen(item) {
    const dropdownItem    = item.parentNode,
          dropdownContent = dropdownItem.querySelector(`.${this.contentClass}`);

    if (window.matchMedia(this.mq).matches) {
      this.removeAriaAttributes(item, dropdownContent);
    }
    else {
      this.setAriaAttributes(item, dropdownContent, true);
      item.disabled = false;
    }
  }

  toggleContent(trigger, dropdownContent, opening) {
    const dropdownBlock = trigger.closest('.dropdown-list'),
          focusableElements = dropdownContent.querySelectorAll('button:not([disabled]), a[href], area[href] input:not([disabled]), select:not([disabled]), textarea:not([disabled]), *[tabindex]:not([tabindex="-1"]), object, embed, *[contenteditable]');          ;

    if (!this.isMediumOpen(dropdownBlock)) {
      if (dropdownContent.clientHeight > 0) {
        this.setAriaAttributes(trigger, dropdownContent, true);
        trigger.focus();
      }
      else if (opening) {
        this.setAriaAttributes(trigger, dropdownContent, false);
        focusableElements[0].focus();
      }
    }
  }

  setMediumOpen() {
    if (this.dropdownMediumOpen) {
      let dropdownItems = [...this.element.querySelectorAll(this.dropdownCollapseLabel)];
      dropdownItems.forEach(key => this.resetMqMediumOpen(key));
    }
  }

  init() {
    this.dropdownItem.forEach(key => {
      const dropdownId = key.getAttribute('aria-controls'),
            dropdownContent = document.getElementById(dropdownId);

      key.addEventListener('click', e => {
        e.preventDefault();
        this.toggleContent(key, dropdownContent, true);
      }, false);

      [key, dropdownContent].forEach(el => el.addEventListener('keydown', e => {
        if (e.key === 'Escape') {
          this.toggleContent(key, dropdownContent, false);
        }
      }));
    });

    this.setMediumOpen();

    window.addEventListener('resize', () => {
      this.setMediumOpen();
    });
  }
}

new DropdownList(document.querySelector('.dropdown-list'));
<commit_msg>Remove wrong semicolon<commit_after>'use strict';

class DropdownList {
  constructor(element) {
    this.element = element;
    this.dropdownCollapseLabel = '.dropdown-list__item--collapse > .dropdown-list__label';
    this.dropdownItem = [...this.element.querySelectorAll(this.dropdownCollapseLabel)];
    this.contentClass = 'dropdown-list__content';
    this.mq = '(min-width: 768px)';
    this.mqClass = 'dropdown-list--is-open@screen-m';
    this.dropdownMediumOpen = this.element.classList.contains(this.mqClass);
    this.init();
  }

  setAriaAttributes(label, content, expanded) {
    if (expanded) {
      label.setAttribute('aria-expanded', 'false');
      content.setAttribute('aria-hidden', 'true');
    }
    else {
      label.setAttribute('aria-expanded', 'true');
      content.setAttribute('aria-hidden', 'false');
    }
  }

  removeAriaAttributes(label, content) {
    label.removeAttribute('aria-expanded');
    content.setAttribute('aria-hidden', 'false');
    label.disabled = true;
  }

  isMediumOpen(dropdownBlock) {
    return (dropdownBlock.classList.contains('dropdown-list--is-open@screen-m')) && window.matchMedia(this.mq).matches;
  }

  resetMqMediumOpen(item) {
    const dropdownItem    = item.parentNode,
          dropdownContent = dropdownItem.querySelector(`.${this.contentClass}`);

    if (window.matchMedia(this.mq).matches) {
      this.removeAriaAttributes(item, dropdownContent);
    }
    else {
      this.setAriaAttributes(item, dropdownContent, true);
      item.disabled = false;
    }
  }

  toggleContent(trigger, dropdownContent, opening) {
    const dropdownBlock = trigger.closest('.dropdown-list'),
          focusableElements = dropdownContent.querySelectorAll('button:not([disabled]), a[href], area[href] input:not([disabled]), select:not([disabled]), textarea:not([disabled]), *[tabindex]:not([tabindex="-1"]), object, embed, *[contenteditable]');

    if (!this.isMediumOpen(dropdownBlock)) {
      if (dropdownContent.clientHeight > 0) {
        this.setAriaAttributes(trigger, dropdownContent, true);
        trigger.focus();
      }
      else if (opening) {
        this.setAriaAttributes(trigger, dropdownContent, false);
        focusableElements[0].focus();
      }
    }
  }

  setMediumOpen() {
    if (this.dropdownMediumOpen) {
      let dropdownItems = [...this.element.querySelectorAll(this.dropdownCollapseLabel)];
      dropdownItems.forEach(key => this.resetMqMediumOpen(key));
    }
  }

  init() {
    this.dropdownItem.forEach(key => {
      const dropdownId = key.getAttribute('aria-controls'),
            dropdownContent = document.getElementById(dropdownId);

      key.addEventListener('click', e => {
        e.preventDefault();
        this.toggleContent(key, dropdownContent, true);
      }, false);

      [key, dropdownContent].forEach(el => el.addEventListener('keydown', e => {
        if (e.key === 'Escape') {
          this.toggleContent(key, dropdownContent, false);
        }
      }));
    });

    this.setMediumOpen();

    window.addEventListener('resize', () => {
      this.setMediumOpen();
    });
  }
}

new DropdownList(document.querySelector('.dropdown-list'));
<|endoftext|>


<commit_before>import ComponentActions from './../../../actions/component';
import OptionsHelper from 'utils/helpers/options-helper';
import { assign } from 'lodash';

export default (definition) => {
  definition.propValues.fieldHelp = 'This text provides help for the input.';
  definition.propValues.label = 'Example ' + definition.name;
  definition.propValues.labelHelp = 'This text provides more information for the label.';

  definition.propOptions.labelAlign = OptionsHelper.alignBinary;

  definition.hiddenProps = definition.hiddenProps.concat(['warnings', 'validations', 'info', 'value']);

  definition.propRequires.labelInline = 'label';
  definition.propRequires.labelWidth = 'labelInline';
  definition.propRequires.labelAlign = 'labelInline';

  definition.stubAction('onChange', 'value');

  definition.propTypes = assign({}, definition.propTypes, {
    fieldHelp: "Node",
    fieldHelpInline: "Boolean",
    inputWidth: "Number",
    label: "String",
    labelAlign: "String",
    labelHelp: "String",
    labelInline: "Boolean",
    labelWidth: "Number",
    validations: "Array",
    warnings: "Array"
  });

  definition.propDescriptions = assign({}, definition.propDescriptions, {
    fieldHelp: "Displays additional text below the input to provide help to the user.",
    fieldHelpInline: "Displays fieldHelp inline with the checkbox/radio button.",
    inputWidth: "A number representing the percentage/ratio of width with the label. Works best with inline labels.",
    label: "Outputs a label for the input.",
    labelAlign: "Align the label either 'left' or 'right'. Only works with inline labels.",
    labelHelp: "Output an info icon next to the label to display additional help to the user.",
    labelInline: "Displays the label inline with the input.",
    labelWidth: "A number representing the percentage/ratio of width with the input. Works best with inline labels.",
    validations: "An array of validations to apply to the input.",
    warnings: "An array of warnings to apply to the input."
  });
}
<commit_msg>updated input definition description<commit_after>import ComponentActions from './../../../actions/component';
import OptionsHelper from 'utils/helpers/options-helper';
import { assign } from 'lodash';

export default (definition) => {
  definition.propValues.fieldHelp = 'This text provides help for the input.';
  definition.propValues.label = 'Example ' + definition.name;
  definition.propValues.labelHelp = 'This text provides more information for the label.';

  definition.propOptions.labelAlign = OptionsHelper.alignBinary;

  definition.hiddenProps = definition.hiddenProps.concat(['warnings', 'validations', 'info', 'value']);

  definition.propRequires.labelInline = 'label';
  definition.propRequires.labelWidth = 'labelInline';
  definition.propRequires.labelAlign = 'labelInline';

  definition.stubAction('onChange', 'value');

  definition.propTypes = assign({}, definition.propTypes, {
    fieldHelp: "Node",
    fieldHelpInline: "Boolean",
    inputWidth: "Number",
    label: "String",
    labelAlign: "String",
    labelHelp: "String",
    labelInline: "Boolean",
    labelWidth: "Number",
    validations: "Array",
    warnings: "Array"
  });

  definition.propDescriptions = assign({}, definition.propDescriptions, {
    fieldHelp: "Displays additional information below the input to provide help to the user.",
    fieldHelpInline: "Displays fieldHelp inline with the checkbox/radio button.",
    inputWidth: "A number representing the percentage/ratio of width with the label. Works best with inline labels.",
    label: "Outputs a label for the input.",
    labelAlign: "Align the label either 'left' or 'right'. Only works with inline labels.",
    labelHelp: "Output an info icon next to the label to display additional help to the user.",
    labelInline: "Displays the label inline with the input.",
    labelWidth: "A number representing the percentage/ratio of width with the input. Works best with inline labels.",
    validations: "An array of validations to apply to the input.",
    warnings: "An array of warnings to apply to the input."
  });
}
<|endoftext|>


<commit_before>goog.provide('gmfapp.objecteditinghub');

goog.require('goog.asserts');
/** @suppress {extraRequire} */
goog.require('ngeo.proj.EPSG21781');
goog.require('gmf.ObjectEditingManager');
goog.require('gmf.Themes');
goog.require('gmf.XSDAttributes');
goog.require('ol.format.WFS');

/** @type {!angular.Module} **/
gmfapp.module = angular.module('gmfapp', ['gmf']);

gmfapp.module.value('gmfTreeUrl',
    'https://geomapfish-demo.camptocamp.net/2.1/wsgi/themes?version=2&background=background');

gmfapp.module.value('gmfLayersUrl',
    'https://geomapfish-demo.camptocamp.net/2.1/wsgi/layers/');

/**
 * @param {angular.$http} $http Angular $http service.
 * @param {angular.$q} $q Angular $q service.
 * @param {!angular.Scope} $scope Angular scope.
 * @param {gmf.Themes} gmfThemes The gmf themes service.
 * @param {gmf.XSDAttributes} gmfXSDAttributes The gmf XSDAttributes service.
 * @constructor
 * @ngInject
 */
gmfapp.MainController = function($http, $q, $scope, gmfThemes, gmfXSDAttributes) {

  /**
   * @type {angular.$http}
   * @private
   */
  this.http_ = $http;

  /**
   * @type {angular.$q}
   * @private
   */
  this.q_ = $q;

  /**
   * @type {gmf.Themes}
   * @private
   */
  this.gmfThemes_ = gmfThemes;

  /**
   * @type {gmf.XSDAttributes}
   * @private
   */
  this.gmfXSDAttributes_ = gmfXSDAttributes;

  /**
   * @type {Array.<string>} List of example and application urls that contain
   *     ObjectEditing tools.
   * @export
   */
  this.urls = [
    {
      'name': 'oeedit app. (hosted)',
      'url': 'apps/oeedit/'
    },
    {
      'name': 'oeedit app. (dev)',
      'url': '../apps/oeedit/'
    },
    {
      'name': 'example',
      'url': 'objectediting.html'
    }
  ];

  /**
   * @type {string} OE viewer application base url when developping.
   * @private
   */
  this.viewerUrlDev_ = '../apps/oeview/';

  /**
   * @type {string} OE viewer application base url when hosted.
   * @private
   */
  this.viewerUrlHosted_ = 'apps/oeview/';

  /**
   * @type {Object.<string, string>}
   * @export
   */
  this.selectedUrl = this.urls[0];

  /**
   * @type {gmfThemes.GmfOgcServers} ogcServers OGC servers.
   * @private
   */
  this.gmfServers_;

  /**
   * @type {gmfThemes.GmfOgcServer} ogcServer OGC server to use.
   * @private
   */
  this.gmfServer_;

  /**
   * @type {Array.<gmfThemes.GmfLayerWMS>}
   * @export
   */
  this.gmfLayerNodes = [];

  /**
   * @type {?gmfThemes.GmfLayerWMS}
   * @export
   */
  this.selectedGmfLayerNode = null;

  /**
   * @type {Object.<number, Array.<ol.Feature>>}
   * @export
   */
  this.featuresCache_ = {};

  /**
   * @type {Array.<ol.Feature>}
   * @export
   */
  this.features = null;

  /**
   * @type {?ol.Feature}
   * @export
   */
  this.selectedFeature = null;

  /**
   * @type {Object.<number, string>}
   * @private
   */
  this.geomTypeCache_ = {};

  /**
   * @type {?string}
   * @export
   */
  this.selectedGeomType = null;

  $scope.$watch(
    () => this.selectedGmfLayerNode,
    (newVal, oldVal) => {
      this.selectedFeature = null;

      if (newVal) {
        this.getFeatures_(newVal).then(
          this.handleGetFeatures_.bind(this, newVal)
        );
        this.getGeometryType_(newVal).then(
          this.handleGetGeometryType_.bind(this, newVal)
        );
      }
    }
  );

  /**
   * @type {string}
   * @export
   */
  this.themeName = 'ObjectEditing';

  this.gmfThemes_.loadThemes();

  this.gmfThemes_.getOgcServersObject().then((ogcServers) => {

    // (1) Set OGC servers
    this.gmfServers_ = ogcServers;

    this.gmfThemes_.getThemesObject().then((themes) => {
      if (!themes) {
        return;
      }

      let i, ii;

      // (2) Find OE theme
      let theme;
      for (i = 0, ii = themes.length; i < ii; i++) {
        if (themes[i].name === this.themeName) {
          theme = themes[i];
          break;
        }
      }

      if (!theme) {
        return;
      }

      // (3) Get first group node
      const groupNode = theme.children[0];

      // (4) Set OGC server, which must support WFS for this example to work
      const gmfServer = this.gmfServers_[groupNode.ogcServer];
      if (gmfServer && gmfServer.wfsSupport === true && gmfServer.urlWfs) {
        this.gmfServer_ = gmfServer;
      } else {
        return;
      }

      const gmfLayerNodes = [];
      for (i = 0, ii = groupNode.children.length; i < ii; i++) {
        if (groupNode.children[i].metadata.identifierAttributeField) {
          gmfLayerNodes.push(groupNode.children[i]);
        }
      }

      // (5) Set layer nodes
      this.gmfLayerNodes = gmfLayerNodes;

      // (6) Select 'polygon' for the purpose of simplifying the demo
      this.selectedGmfLayerNode = this.gmfLayerNodes[1];

    });
  });

};

/**
 * @export
 */
gmfapp.MainController.prototype.runEditor = function() {

  const geomType = this.selectedGeomType;
  const feature = this.selectedFeature;
  const layer = this.selectedGmfLayerNode.id;
  const property = this.selectedGmfLayerNode.metadata.identifierAttributeField;
  goog.asserts.assert(property !== undefined);
  const id = feature.get(property);

  const params = {};
  params[gmf.ObjectEditingManager.Param.GEOM_TYPE] = geomType;
  params[gmf.ObjectEditingManager.Param.ID] = id;
  params[gmf.ObjectEditingManager.Param.LAYER] = layer;
  params[gmf.ObjectEditingManager.Param.THEME] = this.themeName;
  params[gmf.ObjectEditingManager.Param.PROPERTY] = property;

  const url = gmfapp.MainController.appendParams(this.selectedUrl['url'], params);
  window.open(url);
};

/**
 * @export
 */
gmfapp.MainController.prototype.runViewerDev = function() {
  this.runViewer_(this.viewerUrlDev_);
};

/**
 * @export
 */
gmfapp.MainController.prototype.runViewerHosted = function() {
  this.runViewer_(this.viewerUrlHosted_);
};

/**
 * @param {string} baseUrl Base url of the viewer.
 * @private
 */
gmfapp.MainController.prototype.runViewer_ = function(baseUrl) {

  const node = this.selectedGmfLayerNode;
  const nodeId = node.id;
  const nodeName = node.name;
  const nodeIdAttrFieldName = node.metadata.identifierAttributeField;
  goog.asserts.assert(nodeIdAttrFieldName !== undefined);
  const ids = [];

  const features = this.featuresCache_[nodeId];
  for (let i = 0, ii = features.length; i < ii; i++) {
    ids.push(
      features[i].get(nodeIdAttrFieldName)
    );
  }

  const params = {};
  params['wfs_layer'] = nodeName;
  params[`wfs_${nodeIdAttrFieldName}`] = ids.join(',');

  const url = gmfapp.MainController.appendParams(baseUrl, params);
  window.open(url);
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @return {angular.$q.Promise} The promise attached to the deferred object.
 * @private
 */
gmfapp.MainController.prototype.getFeatures_ = function(gmfLayerNode) {

  this.getFeaturesDeferred_ = this.q_.defer();

  const features = this.getFeaturesFromCache_(gmfLayerNode);

  if (features) {
    this.getFeaturesDeferred_.resolve();
  } else {
    this.issueGetFeatures_(gmfLayerNode);
  }

  return this.getFeaturesDeferred_.promise;
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @private
 */
gmfapp.MainController.prototype.issueGetFeatures_ = function(gmfLayerNode) {

  const id = gmfLayerNode.id;

  const url = gmfapp.MainController.appendParams(
    this.gmfServer_.urlWfs,
    {
      'SERVICE': 'WFS',
      'REQUEST': 'GetFeature',
      'VERSION': '1.1.0',
      'TYPENAME': gmfLayerNode.layers
    }
  );

  this.http_.get(url).then((response) => {
    const features = new ol.format.WFS().readFeatures(response.data);
    this.featuresCache_[id] = features;
    this.getFeaturesDeferred_.resolve();
  });
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @private
 */
gmfapp.MainController.prototype.handleGetFeatures_ = function(gmfLayerNode) {
  const features = /** @type Array.<ol.Feature> */ (
    this.getFeaturesFromCache_(gmfLayerNode));
  this.features = features;
  this.selectedFeature = this.features[0];
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @return {?Array.<ol.Feature>} List of features
 * @private
 */
gmfapp.MainController.prototype.getFeaturesFromCache_ = function(gmfLayerNode) {
  const id = gmfLayerNode.id;
  const features = this.featuresCache_[id] || null;
  return features;
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @return {angular.$q.Promise} The promise attached to the deferred object.
 * @private
 */
gmfapp.MainController.prototype.getGeometryType_ = function(gmfLayerNode) {

  this.getGeometryTypeDeferred_ = this.q_.defer();

  const geomType = this.getGeometryTypeFromCache_(gmfLayerNode);

  if (geomType) {
    this.getGeometryTypeDeferred_.resolve();
  } else {
    this.issueGetAttributesRequest_(gmfLayerNode);
  }

  return this.getGeometryTypeDeferred_.promise;
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @private
 */
gmfapp.MainController.prototype.issueGetAttributesRequest_ = function(
  gmfLayerNode
) {

  this.gmfXSDAttributes_.getAttributes(gmfLayerNode.id).then(
    function(gmfLayerNode, attributes) {
      // Get geom type from attributes and set
      const geomAttr = ngeo.format.XSDAttribute.getGeometryAttribute(attributes);
      if (geomAttr && geomAttr.geomType) {
        this.geomTypeCache_[gmfLayerNode.id] = geomAttr.geomType;
        this.getGeometryTypeDeferred_.resolve();
      }
    }.bind(this, gmfLayerNode)
  );

};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @private
 */
gmfapp.MainController.prototype.handleGetGeometryType_ = function(gmfLayerNode) {
  const geomType = /** @type {string} */ (
    this.getGeometryTypeFromCache_(gmfLayerNode));
  this.selectedGeomType = geomType;
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @return {?string} The type of geometry.
 * @private
 */
gmfapp.MainController.prototype.getGeometryTypeFromCache_ = function(
  gmfLayerNode
) {
  const id = gmfLayerNode.id;
  const geomType = this.geomTypeCache_[id] || null;
  return geomType;
};

/**
 * Appends query parameters to a URI.
 *
 * @param {string} uri The original URI, which may already have query data.
 * @param {!Object} params An object where keys are URI-encoded parameter keys,
 *     and the values are arbitrary types or arrays.
 * @return {string} The new URI.
 */
gmfapp.MainController.appendParams = function(uri, params) {
  const keyParams = [];
  // Skip any null or undefined parameter values
  Object.keys(params).forEach((k) => {
    if (params[k] !== null && params[k] !== undefined) {
      keyParams.push(`${k}=${encodeURIComponent(params[k])}`);
    }
  });
  const qs = keyParams.join('&');
  // remove any trailing ? or &
  uri = uri.replace(/[?&]$/, '');
  // append ? or & depending on whether uri has existing parameters
  uri = uri.indexOf('?') === -1 ? `${uri}?` : `${uri}&`;
  return uri + qs;
};

gmfapp.module.controller('MainController', gmfapp.MainController);
<commit_msg>Fix the examples build<commit_after>goog.provide('gmfapp.objecteditinghub');

goog.require('goog.asserts');
/** @suppress {extraRequire} */
goog.require('ngeo.proj.EPSG21781');
goog.require('gmf.ObjectEditingManager');
goog.require('gmf.Themes');
goog.require('gmf.XSDAttributes');
goog.require('ol.format.WFS');

/** @type {!angular.Module} **/
gmfapp.module = angular.module('gmfapp', ['gmf']);

gmfapp.module.value('gmfTreeUrl',
    'https://geomapfish-demo.camptocamp.net/2.1/wsgi/themes?version=2&background=background');

gmfapp.module.value('gmfLayersUrl',
    'https://geomapfish-demo.camptocamp.net/2.1/wsgi/layers/');

/**
 * @param {angular.$http} $http Angular $http service.
 * @param {angular.$q} $q Angular $q service.
 * @param {!angular.Scope} $scope Angular scope.
 * @param {gmf.Themes} gmfThemes The gmf themes service.
 * @param {gmf.XSDAttributes} gmfXSDAttributes The gmf XSDAttributes service.
 * @constructor
 * @ngInject
 */
gmfapp.MainController = function($http, $q, $scope, gmfThemes, gmfXSDAttributes) {

  /**
   * @type {angular.$http}
   * @private
   */
  this.http_ = $http;

  /**
   * @type {angular.$q}
   * @private
   */
  this.q_ = $q;

  /**
   * @type {gmf.Themes}
   * @private
   */
  this.gmfThemes_ = gmfThemes;

  /**
   * @type {gmf.XSDAttributes}
   * @private
   */
  this.gmfXSDAttributes_ = gmfXSDAttributes;

  /**
   * @type {Array.<string>} List of example and application urls that contain
   *     ObjectEditing tools.
   * @export
   */
  this.urls = [
    {
      'name': 'oeedit app. (hosted)',
      'url': 'apps/oeedit/'
    },
    {
      'name': 'oeedit app. (dev)',
      'url': '../apps/oeedit/'
    },
    {
      'name': 'example',
      'url': 'objectediting.html'
    }
  ];

  /**
   * @type {string} OE viewer application base url when developping.
   * @private
   */
  this.viewerUrlDev_ = '../apps/oeview/';

  /**
   * @type {string} OE viewer application base url when hosted.
   * @private
   */
  this.viewerUrlHosted_ = 'apps/oeview/';

  /**
   * @type {Object.<string, string>}
   * @export
   */
  this.selectedUrl = this.urls[0];

  /**
   * @type {gmfThemes.GmfOgcServers} ogcServers OGC servers.
   * @private
   */
  this.gmfServers_;

  /**
   * @type {gmfThemes.GmfOgcServer} ogcServer OGC server to use.
   * @private
   */
  this.gmfServer_;

  /**
   * @type {Array.<gmfThemes.GmfLayerWMS>}
   * @export
   */
  this.gmfLayerNodes = [];

  /**
   * @type {?gmfThemes.GmfLayerWMS}
   * @export
   */
  this.selectedGmfLayerNode = null;

  /**
   * @type {Object.<number, Array.<ol.Feature>>}
   * @export
   */
  this.featuresCache_ = {};

  /**
   * @type {Array.<ol.Feature>}
   * @export
   */
  this.features = null;

  /**
   * @type {?ol.Feature}
   * @export
   */
  this.selectedFeature = null;

  /**
   * @type {Object.<number, string>}
   * @private
   */
  this.geomTypeCache_ = {};

  /**
   * @type {?string}
   * @export
   */
  this.selectedGeomType = null;

  $scope.$watch(
    () => this.selectedGmfLayerNode,
    (newVal, oldVal) => {
      this.selectedFeature = null;

      if (newVal) {
        this.getFeatures_(newVal).then(
          this.handleGetFeatures_.bind(this, newVal)
        );
        this.getGeometryType_(newVal).then(
          this.handleGetGeometryType_.bind(this, newVal)
        );
      }
    }
  );

  /**
   * @type {string}
   * @export
   */
  this.themeName = 'ObjectEditing';

  this.gmfThemes_.loadThemes();

  this.gmfThemes_.getOgcServersObject().then((ogcServers) => {

    // (1) Set OGC servers
    this.gmfServers_ = ogcServers;

    this.gmfThemes_.getThemesObject().then((themes) => {
      if (!themes) {
        return;
      }

      let i, ii;

      // (2) Find OE theme
      let theme;
      for (i = 0, ii = themes.length; i < ii; i++) {
        if (themes[i].name === this.themeName) {
          theme = themes[i];
          break;
        }
      }

      if (!theme) {
        return;
      }

      // (3) Get first group node
      const groupNode = theme.children[0];

      // (4) Set OGC server, which must support WFS for this example to work
      goog.asserts.assert(groupNode.ogcServer);
      const gmfServer = this.gmfServers_[groupNode.ogcServer];
      if (gmfServer && gmfServer.wfsSupport === true && gmfServer.urlWfs) {
        this.gmfServer_ = gmfServer;
      } else {
        return;
      }

      const gmfLayerNodes = [];
      for (i = 0, ii = groupNode.children.length; i < ii; i++) {
        if (groupNode.children[i].metadata.identifierAttributeField) {
          gmfLayerNodes.push(groupNode.children[i]);
        }
      }

      // (5) Set layer nodes
      this.gmfLayerNodes = gmfLayerNodes;

      // (6) Select 'polygon' for the purpose of simplifying the demo
      this.selectedGmfLayerNode = this.gmfLayerNodes[1];

    });
  });

};

/**
 * @export
 */
gmfapp.MainController.prototype.runEditor = function() {

  const geomType = this.selectedGeomType;
  const feature = this.selectedFeature;
  const layer = this.selectedGmfLayerNode.id;
  const property = this.selectedGmfLayerNode.metadata.identifierAttributeField;
  goog.asserts.assert(property !== undefined);
  const id = feature.get(property);

  const params = {};
  params[gmf.ObjectEditingManager.Param.GEOM_TYPE] = geomType;
  params[gmf.ObjectEditingManager.Param.ID] = id;
  params[gmf.ObjectEditingManager.Param.LAYER] = layer;
  params[gmf.ObjectEditingManager.Param.THEME] = this.themeName;
  params[gmf.ObjectEditingManager.Param.PROPERTY] = property;

  const url = gmfapp.MainController.appendParams(this.selectedUrl['url'], params);
  window.open(url);
};

/**
 * @export
 */
gmfapp.MainController.prototype.runViewerDev = function() {
  this.runViewer_(this.viewerUrlDev_);
};

/**
 * @export
 */
gmfapp.MainController.prototype.runViewerHosted = function() {
  this.runViewer_(this.viewerUrlHosted_);
};

/**
 * @param {string} baseUrl Base url of the viewer.
 * @private
 */
gmfapp.MainController.prototype.runViewer_ = function(baseUrl) {

  const node = this.selectedGmfLayerNode;
  const nodeId = node.id;
  const nodeName = node.name;
  const nodeIdAttrFieldName = node.metadata.identifierAttributeField;
  goog.asserts.assert(nodeIdAttrFieldName !== undefined);
  const ids = [];

  const features = this.featuresCache_[nodeId];
  for (let i = 0, ii = features.length; i < ii; i++) {
    ids.push(
      features[i].get(nodeIdAttrFieldName)
    );
  }

  const params = {};
  params['wfs_layer'] = nodeName;
  params[`wfs_${nodeIdAttrFieldName}`] = ids.join(',');

  const url = gmfapp.MainController.appendParams(baseUrl, params);
  window.open(url);
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @return {angular.$q.Promise} The promise attached to the deferred object.
 * @private
 */
gmfapp.MainController.prototype.getFeatures_ = function(gmfLayerNode) {

  this.getFeaturesDeferred_ = this.q_.defer();

  const features = this.getFeaturesFromCache_(gmfLayerNode);

  if (features) {
    this.getFeaturesDeferred_.resolve();
  } else {
    this.issueGetFeatures_(gmfLayerNode);
  }

  return this.getFeaturesDeferred_.promise;
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @private
 */
gmfapp.MainController.prototype.issueGetFeatures_ = function(gmfLayerNode) {

  const id = gmfLayerNode.id;

  const url = gmfapp.MainController.appendParams(
    this.gmfServer_.urlWfs,
    {
      'SERVICE': 'WFS',
      'REQUEST': 'GetFeature',
      'VERSION': '1.1.0',
      'TYPENAME': gmfLayerNode.layers
    }
  );

  this.http_.get(url).then((response) => {
    const features = new ol.format.WFS().readFeatures(response.data);
    this.featuresCache_[id] = features;
    this.getFeaturesDeferred_.resolve();
  });
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @private
 */
gmfapp.MainController.prototype.handleGetFeatures_ = function(gmfLayerNode) {
  const features = /** @type Array.<ol.Feature> */ (
    this.getFeaturesFromCache_(gmfLayerNode));
  this.features = features;
  this.selectedFeature = this.features[0];
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @return {?Array.<ol.Feature>} List of features
 * @private
 */
gmfapp.MainController.prototype.getFeaturesFromCache_ = function(gmfLayerNode) {
  const id = gmfLayerNode.id;
  const features = this.featuresCache_[id] || null;
  return features;
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @return {angular.$q.Promise} The promise attached to the deferred object.
 * @private
 */
gmfapp.MainController.prototype.getGeometryType_ = function(gmfLayerNode) {

  this.getGeometryTypeDeferred_ = this.q_.defer();

  const geomType = this.getGeometryTypeFromCache_(gmfLayerNode);

  if (geomType) {
    this.getGeometryTypeDeferred_.resolve();
  } else {
    this.issueGetAttributesRequest_(gmfLayerNode);
  }

  return this.getGeometryTypeDeferred_.promise;
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @private
 */
gmfapp.MainController.prototype.issueGetAttributesRequest_ = function(
  gmfLayerNode
) {

  this.gmfXSDAttributes_.getAttributes(gmfLayerNode.id).then(
    function(gmfLayerNode, attributes) {
      // Get geom type from attributes and set
      const geomAttr = ngeo.format.XSDAttribute.getGeometryAttribute(attributes);
      if (geomAttr && geomAttr.geomType) {
        this.geomTypeCache_[gmfLayerNode.id] = geomAttr.geomType;
        this.getGeometryTypeDeferred_.resolve();
      }
    }.bind(this, gmfLayerNode)
  );

};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @private
 */
gmfapp.MainController.prototype.handleGetGeometryType_ = function(gmfLayerNode) {
  const geomType = /** @type {string} */ (
    this.getGeometryTypeFromCache_(gmfLayerNode));
  this.selectedGeomType = geomType;
};

/**
 * @param {gmfThemes.GmfLayerWMS} gmfLayerNode Layer node.
 * @return {?string} The type of geometry.
 * @private
 */
gmfapp.MainController.prototype.getGeometryTypeFromCache_ = function(
  gmfLayerNode
) {
  const id = gmfLayerNode.id;
  const geomType = this.geomTypeCache_[id] || null;
  return geomType;
};

/**
 * Appends query parameters to a URI.
 *
 * @param {string} uri The original URI, which may already have query data.
 * @param {!Object} params An object where keys are URI-encoded parameter keys,
 *     and the values are arbitrary types or arrays.
 * @return {string} The new URI.
 */
gmfapp.MainController.appendParams = function(uri, params) {
  const keyParams = [];
  // Skip any null or undefined parameter values
  Object.keys(params).forEach((k) => {
    if (params[k] !== null && params[k] !== undefined) {
      keyParams.push(`${k}=${encodeURIComponent(params[k])}`);
    }
  });
  const qs = keyParams.join('&');
  // remove any trailing ? or &
  uri = uri.replace(/[?&]$/, '');
  // append ? or & depending on whether uri has existing parameters
  uri = uri.indexOf('?') === -1 ? `${uri}?` : `${uri}&`;
  return uri + qs;
};

gmfapp.module.controller('MainController', gmfapp.MainController);
<|endoftext|>


<commit_before>/*
 * files.js: Instance methods for working with files from AWS S3
 *
 * (C) 2012 Nodejitsu Inc.
 *
 */

var fs = require('fs'),
  filed = require('filed'),
  mime = require('mime'),
  request = require('request'),
  utile = require('utile'),
  qs = require('querystring'),
  base = require('../../../core/storage'),
  AzureConstants = require('../../utils/constants'),
  pkgcloud = require('../../../../../lib/pkgcloud'),
  storage = pkgcloud.providers.azure2.storage;

//
// ### function removeFile (container, file, callback)
// #### @container {string} Name of the container to destroy the file in
// #### @file {string} Name of the file to destroy.
// #### @callback {function} Continuation to respond to when complete.
// Destroys the `file` in the specified `container`.
//
exports.removeFile = function (container, file, callback) {
  if (container instanceof storage.Container) {
    container = container.name;
  }

  if (file instanceof storage.File) {
    file = file.name;
  }

  this.request('DELETE', [container, file], callback, function (body, res) {
    callback(null, res.statusCode == 204);
  });
};

exports.upload = function (options, callback) {
  if (typeof options === 'function' && !callback) {
    callback = options;
    options = {};
  }

  var container = options.container,
    path,
    rstream,
    lstream;

  if (container instanceof storage.Container) {
    container = container.name;
  }

  options.headers = options.headers || {};

  if (options.local) {
    lstream = filed(options.local);
    options.headers['content-length'] = fs.statSync(options.local).size;
  }
  else if (options.stream) {
    lstream = options.stream;
  }

  if (options.headers && !options.headers['content-type'] && options.remote) {
    options.headers['content-type'] = mime.lookup(options.remote);
  }

  options.headers['x-ms-blob-type'] = AzureConstants.BlobConstants.BlobTypes.BLOCK;

  path = [container + '/' + options.remote];
  if(options.azureBlockId) {
    path[1] = '?comp=block&blockid=' + encodeURIComponent(options.azureBlockId);
  }

  if (options.headers['content-length'] !== undefined) {
    // Regular upload
    rstream = this.request({
      method: 'PUT',
      upload: true,
      path: path,
      headers: options.headers || {}
    }, callback, function (body, res) {
      callback(null, res.statusCode === 200 || res.statusCode === 201);
    });
  } else {
    // Multi-part, 5mb chunk upload
    rstream = this.multipartUpload(options, callback);
  }

  if (lstream) lstream.pipe(rstream);

  return rstream;
};

var getBlockId = function(a, b) {
  return "block" + ((1e15 + a + "").slice(-b));
};

exports.multipartUpload = function (options, callback) {
  var self = this,
    container = options.container,
    chunk = AzureConstants.BlobConstants.DEFAULT_WRITE_BLOCK_SIZE_IN_BYTES,
    numBlocks = 0,
    chunksFinished = [],
    stream = new storage.ChunkedStream(chunk),
    ended = false;

  if (container instanceof storage.Container) {
    container = container.name;
  }

  stream.on('data', function(data) {
    stream.pause();
    options.azureBlockId = getBlockId(numBlocks++, 15);
    options.headers['content-length'] = data.length;
    console.log(data.length);

    var next = function(body, res) {
      if(!ended) {
        stream.resume();
      } else {
        self.sendBlockList(options, numBlocks, callback);
      }
    };

    var rstream = self.upload(options, next);
    rstream.write(data);
    rstream.end();
  });

  stream.on('end', function(data) {
    console.log('stream end');
    ended = true;
  });

  return stream;
};

exports.sendBlockList = function(options, numBlocks, callback) {
  var body,
    container = options.container;

  if (container instanceof storage.Container) {
    container = container.name;
  }

  options.headers = options.headers || {};

  // remove x-ms-blob-type header or request will fail
  if(options.headers['x-ms-blob-type']) {
    delete options.headers['x-ms-blob-type'];
  }

  if(options.headers['content-type']) {
    options.headers['x-ms-blob-content-type'] = options.headers['content-type'];
  } else if (options.remote) {
    options.headers['x-ms-blob-content-type'] = mime.lookup(options.remote);
  }

  path = [container + '/' + options.remote];
  path[1] = '?comp=blocklist';

  body = '<?xml version="1.0" encoding="utf-8"?>';
  body += '<BlockList>';
  for(var i = 0; i < numBlocks; i++) {
    body += '<Latest>' + encodeURIComponent(getBlockId(i,15)) + '</Latest>';
  }
  body += '</BlockList>';

  console.log(body);
  options.headers['content-length'] = body.length;

  this.request({
    method: 'PUT',
    path: path,
    body: body,
    headers: options.headers
  }, callback, function (body, res) {
    callback(null, res.statusCode === 201);
  });
};

exports.multipartUpload2 = function (options, callback) {
  var self = this,
    container = options.container,
    chunk = AzureConstants.BlobConstants.DEFAULT_WRITE_BLOCK_SIZE_IN_BYTES,
    chunksStarted = 0,
    chunksFinished = [],
    stream = new storage.ChunkedStream(chunk),
    ended = false;

  if (container instanceof storage.Container) {
    container = container.name;
  }

  // We're doing a lot of parallel stuff there,
  // but callback should be called only once
  function cb() {
    if (cb.called) return;
    cb.called = true;

    callback.apply(this, arguments);
  };
  cb.called = false;

  // Wait for first data event, probably file is less than 5 mbs and
  // we don't need that multipart thing at all
  stream.once('data', function(data) {
    // Good case - all data fits in one chunk
    if (data.length < chunk) {
      options.headers['content-length'] = data.length;

      // Upload with default method once again
      var rstream = self.upload(options, cb);
      rstream.write(data);
      rstream.end();

      return;
    }

    stream.pause();
    self.xmlRequest(
      'POST',
      [ container, options.remote + '?uploads' ],
      cb,
      function (body, res) {
        if (res.statusCode !== 200) return cb(res.statusCode);

        // Upload rest
        function onChunk(chunk) {
          stream.pause();
          uploadChunk(body.UploadId, chunk, function(err, chunk) {
            if (err) return cb(err);

            finish(chunk);
            stream.resume();
          });
        }
        stream.on('data', onChunk);

        // Upload existing chunk
        onChunk(data);
      }
    );
  });

  stream.on('end', function() {
    ended = true;
    finish();
  });

  function uploadChunk(uploadId, data, callback) {
    // Ignore empty chunks
    if (data.length === 0) return;

    var id = ++chunksStarted,
      chunk = {
        uploadId: uploadId,
        id: id,
        etag: null
      };

    var stream = self.request({
      method: 'PUT',
      upload: true,
      path: [
        container,
        options.remote + '?' + qs.stringify({
          partNumber: id,
          uploadId: uploadId
        })
      ],
      upload: true,
      headers: utile.mixin({}, options.headers, {
        'content-length': data.length
      })
    }, callback, function (body, res) {
      if (res.statusCode != 200) return callback(res.statusCode);

      chunk.etag = res.headers.etag;
      callback(null, chunk);
    });
    stream.write(data);
    stream.end();
  };

  function finish(chunk) {
    if (chunk) chunksFinished.push(chunk);

    // We must send request only if:
    //  - stream was ended
    //  - we was doing multipart request
    //  - all chunks were uploaded
    if (!ended ||
      chunksFinished.length === 0 ||
      chunksFinished.length !== chunksStarted) {
      return;
    }

    // Sort chunks in ascending order
    chunksFinished.sort(function(a, b) {
      return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
    });

    var body = '<CompleteMultipartUpload>' +
      chunksFinished.map(function(chunk) {
        return '<Part>' +
          '<PartNumber>' + chunk.id + '</PartNumber>' +
          '<ETag>' + chunk.etag + '</ETag>' +
          '</Part>';
      }).join('') +
      '</CompleteMultipartUpload>';

    // Send "Complete Multipart Upload" request
    self.request({
      method: 'POST',
      path: [
        container,
        options.remote + '?' + qs.stringify({
          uploadId: chunksFinished[0].uploadId
        })
      ],
      headers: {
        'Content-Length': Buffer.byteLength(body)
      },
      body: body
    }, cb, function(body, res) {
      cb(null, res.statusCode == 200);
    });
  }

  return stream;
};

exports.download = function (options, callback) {
  var self = this,
    container = options.container,
    lstream,
    rstream;

  if (container instanceof storage.Container) {
    container = container.name;
  }

  if (options.local) {
    lstream = filed(options.local);
  }
  else if (options.stream) {
    lstream = options.stream;
  }

  rstream = this.request({
    path: [container, options.remote],
    download: true
  }, callback, function (body, res) {
    callback(null, new (storage.File)(self, utile.mixin(res.headers, {
      container: container,
      name: options.remote
    })));
  });

  if (lstream) {
    rstream.pipe(lstream);
  }

  return rstream;
};

exports.getFile = function (container, file, callback) {
  var containerName = container instanceof base.Container ? container.name : container,
    self = this;

  this.request({
    method: 'HEAD',
    path: [containerName, file ]
  }, callback, function (body, res) {
    callback(null, new storage.File(self, utile.mixin(res.headers, {
      container: container,
      name: file
    })));
  });
}

exports.getFiles = function (container, download, callback) {
  var containerName = container instanceof base.Container ?
      container.name
      :
      container,
    self = this;

  this.xmlRequest([ containerName ], callback, function (body, res) {
    callback(null, self._toArray(body.Contents).map(function (file) {
      file.container = container;
      return new storage.File(self, file);
    }));
  });
};

<commit_msg>remove dead code<commit_after>/*
 * files.js: Instance methods for working with files from AWS S3
 *
 * (C) 2012 Nodejitsu Inc.
 *
 */

var fs = require('fs'),
  filed = require('filed'),
  mime = require('mime'),
  request = require('request'),
  utile = require('utile'),
  qs = require('querystring'),
  base = require('../../../core/storage'),
  AzureConstants = require('../../utils/constants'),
  pkgcloud = require('../../../../../lib/pkgcloud'),
  storage = pkgcloud.providers.azure2.storage;

//
// ### function removeFile (container, file, callback)
// #### @container {string} Name of the container to destroy the file in
// #### @file {string} Name of the file to destroy.
// #### @callback {function} Continuation to respond to when complete.
// Destroys the `file` in the specified `container`.
//
exports.removeFile = function (container, file, callback) {
  if (container instanceof storage.Container) {
    container = container.name;
  }

  if (file instanceof storage.File) {
    file = file.name;
  }

  this.request('DELETE', [container, file], callback, function (body, res) {
    callback(null, res.statusCode == 204);
  });
};

exports.upload = function (options, callback) {
  if (typeof options === 'function' && !callback) {
    callback = options;
    options = {};
  }

  var container = options.container,
    path,
    rstream,
    lstream;

  if (container instanceof storage.Container) {
    container = container.name;
  }

  options.headers = options.headers || {};

  if (options.local) {
    lstream = filed(options.local);
    options.headers['content-length'] = fs.statSync(options.local).size;
  }
  else if (options.stream) {
    lstream = options.stream;
  }

  if (options.headers && !options.headers['content-type'] && options.remote) {
    options.headers['content-type'] = mime.lookup(options.remote);
  }

  options.headers['x-ms-blob-type'] = AzureConstants.BlobConstants.BlobTypes.BLOCK;

  path = [container + '/' + options.remote];
  if(options.azureBlockId) {
    path[1] = '?comp=block&blockid=' + encodeURIComponent(options.azureBlockId);
  }

  if (options.headers['content-length'] !== undefined) {
    // Regular upload
    rstream = this.request({
      method: 'PUT',
      upload: true,
      path: path,
      headers: options.headers || {}
    }, callback, function (body, res) {
      callback(null, res.statusCode === 200 || res.statusCode === 201);
    });
  } else {
    // Multi-part, 5mb chunk upload
    rstream = this.multipartUpload(options, callback);
  }

  if (lstream) lstream.pipe(rstream);

  return rstream;
};

var getBlockId = function(a, b) {
  return "block" + ((1e15 + a + "").slice(-b));
};

exports.multipartUpload = function (options, callback) {
  var self = this,
    container = options.container,
    chunk = AzureConstants.BlobConstants.DEFAULT_WRITE_BLOCK_SIZE_IN_BYTES,
    numBlocks = 0,
    chunksFinished = [],
    stream = new storage.ChunkedStream(chunk),
    ended = false;

  if (container instanceof storage.Container) {
    container = container.name;
  }

  stream.on('data', function(data) {
    stream.pause();
    options.azureBlockId = getBlockId(numBlocks++, 15);
    options.headers['content-length'] = data.length;
    //console.log(data.length);

    var next = function(body, res) {
      if(!ended) {
        stream.resume();
      } else {
        self.sendBlockList(options, numBlocks, callback);
      }
    };

    var rstream = self.upload(options, next);
    rstream.write(data);
    rstream.end();
  });

  stream.on('end', function(data) {
    //console.log('stream end');
    ended = true;
  });

  return stream;
};

exports.sendBlockList = function(options, numBlocks, callback) {
  var body,
    container = options.container;

  if (container instanceof storage.Container) {
    container = container.name;
  }

  options.headers = options.headers || {};

  // remove x-ms-blob-type header or request will fail
  if(options.headers['x-ms-blob-type']) {
    delete options.headers['x-ms-blob-type'];
  }

  if(options.headers['content-type']) {
    options.headers['x-ms-blob-content-type'] = options.headers['content-type'];
  } else if (options.remote) {
    options.headers['x-ms-blob-content-type'] = mime.lookup(options.remote);
  }

  path = [container + '/' + options.remote];
  path[1] = '?comp=blocklist';

  body = '<?xml version="1.0" encoding="utf-8"?>';
  body += '<BlockList>';
  for(var i = 0; i < numBlocks; i++) {
    body += '<Latest>' + encodeURIComponent(getBlockId(i,15)) + '</Latest>';
  }
  body += '</BlockList>';

  //console.log(body);
  options.headers['content-length'] = body.length;

  this.request({
    method: 'PUT',
    path: path,
    body: body,
    headers: options.headers
  }, callback, function (body, res) {
    callback(null, res.statusCode === 201);
  });
};

exports.download = function (options, callback) {
  var self = this,
    container = options.container,
    lstream,
    rstream;

  if (container instanceof storage.Container) {
    container = container.name;
  }

  if (options.local) {
    lstream = filed(options.local);
  }
  else if (options.stream) {
    lstream = options.stream;
  }

  rstream = this.request({
    path: [container, options.remote],
    download: true
  }, callback, function (body, res) {
    callback(null, new (storage.File)(self, utile.mixin(res.headers, {
      container: container,
      name: options.remote
    })));
  });

  if (lstream) {
    rstream.pipe(lstream);
  }

  return rstream;
};

exports.getFile = function (container, file, callback) {
  var containerName = container instanceof base.Container ? container.name : container,
    self = this;

  this.request({
    method: 'HEAD',
    path: [containerName, file ]
  }, callback, function (body, res) {
    callback(null, new storage.File(self, utile.mixin(res.headers, {
      container: container,
      name: file
    })));
  });
}

exports.getFiles = function (container, download, callback) {
  var containerName = container instanceof base.Container ?
      container.name
      :
      container,
    self = this;

  this.xmlRequest([ containerName ], callback, function (body, res) {
    callback(null, self._toArray(body.Contents).map(function (file) {
      file.container = container;
      return new storage.File(self, file);
    }));
  });
};

<|endoftext|>


<commit_before>import webpack from 'webpack';
import webpackDevMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-hot-middleware';
import webpackConfig from '../../../webpack/webpack.dev.js';

const webpackCompiler = webpack(webpackConfig);

// enable webpack middleware for hot-reloads in development
export default function useWebpackMiddleware(app) {

    log.app("Bundling client code...")
    app.use(webpackDevMiddleware(webpackCompiler, {
        publicPath: webpackConfig.output.publicPath,
        stats: {
            colors: true,
            chunks: false,
            'errors-only': true
        }
    }));

    app.use(webpackHotMiddleware(webpackCompiler));

    return app;
}
<commit_msg>tweak(server): use aliased import path on webpack middleware<commit_after>import webpack from 'webpack';
import webpackDevMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-hot-middleware';
import config from '-/webpack/webpack.dev.js';

const webpackCompiler = webpack(config);

// enable webpack middleware for hot-reloads in development
export default function useWebpackMiddleware(app) {

    log.app("Bundling client code...")
    app.use(webpackDevMiddleware(webpackCompiler, {
        publicPath: config.output.publicPath,
        stats: {
            colors: true,
            chunks: false,
            'errors-only': true
        }
    }));

    app.use(webpackHotMiddleware(webpackCompiler));

    return app;
}
<|endoftext|>


<commit_before>"use strict";

require("treemap/lib/searchBar.js").init();
<commit_msg>Fix searchBar.js entry module.<commit_after>"use strict";

require("treemap/lib/searchBar.js").initDefaults();
<|endoftext|>


<commit_before>var buildData = null;
var detailedView = false;
var searchView = false;
var dataLocation = './data/';
var dataType = '.json';
var fileNames = ["21677_fbl_impressive","21677_fbl_appx","21677_rsmain","21677_fbl_ninjacat","950_fbl_chicago"];

// Array of JSON files we want to load
var jsonFiles = new Array(); //["./data/17522_fbl_impressive.json", "./data/17521_rsmain.json", "./data/17522_fbl_appx.json"];

document.addEventListener("DOMContentLoaded", function(){

  var ttme = 800;
if (window.location.pathname.match('index')) ttme = 200;
if (window.location.pathname.match('searchResults')) ttme = 200;
if (window.location.pathname.match('fullDetails')) ttme = 200;

  setTimeout(function(){

  for(i = 0; i < fileNames.length; i++){
    jsonFiles.push(dataLocation + fileNames[i] + dataType);
    var terms = fileNames[i].split("_");
    for(j = 0; j< terms.length; j++)
    {
      addSearchTerm(terms[j]);
    }
  }

  if (window.location.pathname == "/index.htm") {
    displayFavorites();

    searchView = false;
    detailedView = false;

  } else if (window.location.pathname.indexOf("fullDetails.htm") !== -1) {
    console.log("detailed view!");
    searchView = false;
    detailedView = true;

    var searchString = window.location.search.split("=")[1];
    var file = "./data/" + searchString + ".json"
    getBuildData(file);
  } else if (window.location.pathname.indexOf("searchResults.htm") !== -1) {
    console.log("Search view!");

    searchView = true;
    detailedView = false;

    //var searchString = new URLSearchParams(window.location.search).get("query");
    var searchString = window.location.search.split("=")[1];
    console.log("The thing we are searching for is: " + searchString);

    findResults(searchString);
  } else if (window.location.pathname == "/summaryPage.htm") {
    processData(jsonFiles);

    searchView = false;
    detailedView = false;
  }
  }, ttme)
});

// Identify which JSON files contain the data we are looking for!
function findResults(query) {
  var filteredResults = [];

  for (var i = 0; i < jsonFiles.length; i++) {
    var fileName = jsonFiles[i];

    if (fileName.indexOf(query) !== -1) {
      filteredResults.push(fileName);
    }
  }

  console.log(filteredResults);
  processData(filteredResults);
}

// XHR request to load common templates
function loadHandlebarsTemplate(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            var raw = xhr.responseText;
            var compiled = Handlebars.compile(raw);
            callback(compiled);
        }
    };
    xhr.send();
}

//
// Listen to clicks on the favorite icon
//
function setupFavoritesEvents() {
  var favorites = document.querySelectorAll(".favorite");

  for (var i = 0; i < favorites.length; i++) {
    var favorite = favorites[i];
    favorite.addEventListener("click", processFavorite, false);
  }
}

// keep track of all the files we currently have
// favorited and add/remove them
function processFavorite(e) {
  e.preventDefault();

  var favoriteFile = e.target.getAttribute("data-file");
  var favoritesArray;

  if (localStorage.getItem("favorites")) {
    console.log("creating favorites!");
    favoritesArray = JSON.parse(localStorage.getItem("favorites"));
  } else {
    favoritesArray = [];
  }

  if (favoritesArray.includes(favoriteFile)) {
    var index = favoritesArray.indexOf(favoriteFile);
    favoritesArray.splice(index, 1);

    var favoriteStar = document.querySelector(".favorite[data-file='" + favoriteFile + "']");
    favoriteStar.classList.toggle("hideFavorite");

  } else {
    favoritesArray.push(favoriteFile);
  }

  localStorage.setItem("favorites", JSON.stringify(favoritesArray));
}

// Store our important DOM elements
var template = document.querySelector("#dataContent");
var contentElement = document.querySelector("#content");
if(document.getElementById('dataViews')){
  contentElement = document.getElementById('dataViews');
}
// The entry point to what our app does
function processData(fileArray) {
  for (var i = 0; i < fileArray.length; i++) {
    var jsonFile = fileArray[i];
    getBuildData(jsonFile);
  }
}

// Sample function to get Windows Build data
function getBuildData(file) {
    // Create XHR object
    var xhr = new XMLHttpRequest();
    xhr.dataFile = file;
    xhr.addEventListener("load", transferComplete);
    xhr.open("GET", file);
    xhr.send();
}

// Windows Build data is retrieved, display it
function transferComplete(evt) {
    buildData = JSON.parse(evt.srcElement.responseText);

    var clonedElement = template.content.cloneNode(true);
    clonedElement.querySelector(".linkDetails").setAttribute("href", "fullDetails.htm?details=" + buildData.builds[0].branch.file);
    clonedElement.querySelector(".branchName").innerText = buildData.builds[0].branch.name;
    clonedElement.querySelector(".buildNumber").innerText = buildData.builds[0].build.display;
    // deal with the favorite star
    var starElement = clonedElement.querySelector(".favorite");

    if (starElement) {
      starElement.setAttribute("data-file", evt.srcElement.dataFile);
    }

    var favoritesArray = [];

    if (localStorage.getItem("favorites")) {
      favoritesArray = JSON.parse(localStorage.getItem("favorites"));
    } else {
      console.log("No Favorites!");
    }

    for (var i = 0; i < favoritesArray.length; i++) {
      var favoriteFile = favoritesArray[i];

      if (favoriteFile == evt.srcElement.dataFile) {
        clonedElement.querySelector(".favorite").classList.toggle("hideFavorite");
      }
    }

    clonedElement.querySelector(".releaseValue").innerText = buildData.builds[0].build.releaseScore;
    clonedElement.querySelector(".hours").innerText = buildData.builds[0].build.hours;
    clonedElement.querySelector(".hotbugs").innerText = buildData.builds[0].build.hotbugs;
    clonedElement.querySelector(".triage").innerText = buildData.builds[0].build.triage;
    clonedElement.querySelector(".warnings").innerText = buildData.builds[0].build.warnings;
    clonedElement.querySelector(".arch").innerText = buildData.builds[0].build.platform;
    clonedElement.querySelector(".passrate").innerText = buildData.builds[0].build.passrate;

    //
    // NOTE: We don't want to send the entire JSON file again. We only
    //       need to send the parsed data. This is a TODO item that
    //       hasn't been addressed yet.
    //
    //if (detailedView == true) {
      createBarChart(clonedElement.querySelector(".chart"), evt.srcElement.dataFile);
    //}
    contentElement.appendChild(clonedElement);

    setupFavoritesEvents();

    // if (window.location.pathname == "/summaryPage.htm") {
    //   setupCarousel();
    // }

    //updateFavoriteStars();
}

function displayFavorites() {
  var favoritesArray;

  if (localStorage.getItem("favorites")) {
    favoritesArray = JSON.parse(localStorage.getItem("favorites"));
    processData(favoritesArray);
  } else {
    console.log("No Favorites!");
  }
}

//
// We want to visually differentiate builds you've favorited
// from builds you have not favorited
//
function updateFavoriteStars() {
  var favoritesArray;

  if (localStorage.getItem("favorites")) {
    favoritesArray = JSON.parse(localStorage.getItem("favorites"));

    for (var i = 0; i < favoritesArray.length; i++) {
      var favoriteFile = favoritesArray[i];
      var favoriteStar = document.querySelector(".favorite[data-file='" + favoriteFile + "']");
      favoriteStar.classList.toggle("hideFavorite");
    }
  }
}

var currentItem = 0;
var items;

var container = document.querySelector("#content");

//carousel sript
if(document.getElementById('dataViews')) {
var dataviews = document.getElementById('dataViewWrapper');

var changeFactor = function(dir){
    var currentValue = Number(dataviews.getAttribute('data-datapos'));

 if(dir === "lower") {

  dataviews.setAttribute('data-datapos', (currentValue === 0?0:currentValue-1))
 }else{

  dataviews.setAttribute('data-datapos', (currentValue === 4?4:currentValue+1))

 }

}

///listeners
document.getElementById('left').addEventListener('click', function(){
  changeFactor('lower')
})
document.getElementById('right').addEventListener('click', function(){
  changeFactor('higher')
})

var mode = 'system';
function modeSwitch(ev) {

    mode = ev.target.displayText;
}
if (typeof Windows != 'undefined') {

    // Modify System Defaults to Only Show Volume and Next/Prev Track as per guidance.
    // https://docs.microsoft.com/en-us/windows/uwp/input-and-devices/windows-wheel-interactions

    //initilize dial
    var config = Windows.UI.Input.RadialControllerConfiguration.getForCurrentView();
    config.setDefaultMenuItems([Windows.UI.Input.RadialControllerSystemMenuItemKind.scroll]);
    var controller = Windows.UI.Input.RadialController.createForCurrentView();

    // Add our own item to respond to
    // var mi = Windows.UI.Input.RadialControllerMenuItem.createFromKnownIcon("Undo/Redo", Windows.UI.Input.RadialControllerMenuKnownIcon.undoRedo);
    // mi.addEventListener("invoked", modeSwitch);

    // Add two custom sections for the dial interface
    // If images do not show on Dial, change path to be absolute
    var mi2 = Windows.UI.Input.RadialControllerMenuItem.createFromIcon("Review Builds", Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(new Windows.Foundation.Uri("https://es-tracker.azurewebsites.net/images/dial2.png")));
    var mi3 = Windows.UI.Input.RadialControllerMenuItem.createFromIcon("Release", Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(new Windows.Foundation.Uri("https://es-tracker.azurewebsites.net/images/dial1.png")));
  //push to controler
    controller.menu.items.push(mi2);
    controller.menu.items.push(mi3);

    mi2.addEventListener("invoked", modeSwitch);
    mi3.addEventListener('invoked', modeSwitch);
  //  controller.menu.items.push(mi);

    controller.addEventListener("buttonclicked", function (e) {
     if(mode !== 'Release') return
     document.body.classList.toggle('build');
    });

    controller.addEventListener("rotationchanged", function (e) {
        if(mode !== 'Review Builds') return
        var changeDirection = e.detail[0].rotationDeltaInDegrees;
      if(changeDirection < 0){
        changeFactor('lower')
      }else{
        changeFactor('higher')

      }

      //  log("rotation changed: " + e.detail[0].rotationDeltaInDegrees + " in " + mode);
    });

}

//
///brb code

document.querySelector('.cancelbrb').addEventListener('click', function(){
  document.querySelector('#modal').classList.toggle('hidden')
})

setTimeout(function(){
var sendbuttons = document.querySelectorAll('.sendBuild');

for(var i = 0; i < sendbuttons.length;i++){
sendbuttons[i].addEventListener('click', function(){
    document.querySelector('#modal').classList.toggle('hidden')
})

}

}, 2000)
//
//
//
//
//
//
//
//
//
//
//
//
//
//
 }//end check for last page
<commit_msg>adjust loads<commit_after>var buildData = null;
var detailedView = false;
var searchView = false;
var dataLocation = './data/';
var dataType = '.json';
var fileNames = ["21677_fbl_impressive","21677_fbl_appx","21677_rsmain","21677_fbl_ninjacat","950_fbl_chicago"];

// Array of JSON files we want to load
var jsonFiles = new Array(); //["./data/17522_fbl_impressive.json", "./data/17521_rsmain.json", "./data/17522_fbl_appx.json"];

document.addEventListener("DOMContentLoaded", function(){

  for(i = 0; i < fileNames.length; i++){
    jsonFiles.push(dataLocation + fileNames[i] + dataType);
    var terms = fileNames[i].split("_");
    for(j = 0; j< terms.length; j++)
    {
      addSearchTerm(terms[j]);
    }
  }

  if (window.location.pathname == "/index.htm") {
    displayFavorites();

    searchView = false;
    detailedView = false;

  } else if (window.location.pathname.indexOf("fullDetails.htm") !== -1) {
    console.log("detailed view!");
    searchView = false;
    detailedView = true;

    var searchString = window.location.search.split("=")[1];
    var file = "./data/" + searchString + ".json"
    getBuildData(file);
  } else if (window.location.pathname.indexOf("searchResults.htm") !== -1) {
    console.log("Search view!");

    searchView = true;
    detailedView = false;

    //var searchString = new URLSearchParams(window.location.search).get("query");
    var searchString = window.location.search.split("=")[1];
    console.log("The thing we are searching for is: " + searchString);

    findResults(searchString);
  } else if (window.location.pathname == "/summaryPage.htm") {
    processData(jsonFiles);

    searchView = false;
    detailedView = false;
  }

});

// Identify which JSON files contain the data we are looking for!
function findResults(query) {
  var filteredResults = [];

  for (var i = 0; i < jsonFiles.length; i++) {
    var fileName = jsonFiles[i];

    if (fileName.indexOf(query) !== -1) {
      filteredResults.push(fileName);
    }
  }

  console.log(filteredResults);
  processData(filteredResults);
}

// XHR request to load common templates
function loadHandlebarsTemplate(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            var raw = xhr.responseText;
            var compiled = Handlebars.compile(raw);
            callback(compiled);
        }
    };
    xhr.send();
}

//
// Listen to clicks on the favorite icon
//
function setupFavoritesEvents() {
  var favorites = document.querySelectorAll(".favorite");

  for (var i = 0; i < favorites.length; i++) {
    var favorite = favorites[i];
    favorite.addEventListener("click", processFavorite, false);
  }
}

// keep track of all the files we currently have
// favorited and add/remove them
function processFavorite(e) {
  e.preventDefault();

  var favoriteFile = e.target.getAttribute("data-file");
  var favoritesArray;

  if (localStorage.getItem("favorites")) {
    console.log("creating favorites!");
    favoritesArray = JSON.parse(localStorage.getItem("favorites"));
  } else {
    favoritesArray = [];
  }

  if (favoritesArray.includes(favoriteFile)) {
    var index = favoritesArray.indexOf(favoriteFile);
    favoritesArray.splice(index, 1);

    var favoriteStar = document.querySelector(".favorite[data-file='" + favoriteFile + "']");
    favoriteStar.classList.toggle("hideFavorite");

  } else {
    favoritesArray.push(favoriteFile);
  }

  localStorage.setItem("favorites", JSON.stringify(favoritesArray));
}

// Store our important DOM elements
var template = document.querySelector("#dataContent");
var contentElement = document.querySelector("#content");
if(document.getElementById('dataViews')){
  contentElement = document.getElementById('dataViews');
}
// The entry point to what our app does
function processData(fileArray) {
  for (var i = 0; i < fileArray.length; i++) {
    var jsonFile = fileArray[i];
    getBuildData(jsonFile);
  }
}

// Sample function to get Windows Build data
function getBuildData(file) {
    // Create XHR object
    var xhr = new XMLHttpRequest();
    xhr.dataFile = file;
    xhr.addEventListener("load", transferComplete);
    xhr.open("GET", file);
    xhr.send();
}

// Windows Build data is retrieved, display it
function transferComplete(evt) {
    buildData = JSON.parse(evt.srcElement.responseText);

    var clonedElement = template.content.cloneNode(true);
    clonedElement.querySelector(".linkDetails").setAttribute("href", "fullDetails.htm?details=" + buildData.builds[0].branch.file);
    clonedElement.querySelector(".branchName").innerText = buildData.builds[0].branch.name;
    clonedElement.querySelector(".buildNumber").innerText = buildData.builds[0].build.display;
    // deal with the favorite star
    var starElement = clonedElement.querySelector(".favorite");

    if (starElement) {
      starElement.setAttribute("data-file", evt.srcElement.dataFile);
    }

    var favoritesArray = [];

    if (localStorage.getItem("favorites")) {
      favoritesArray = JSON.parse(localStorage.getItem("favorites"));
    } else {
      console.log("No Favorites!");
    }

    for (var i = 0; i < favoritesArray.length; i++) {
      var favoriteFile = favoritesArray[i];

      if (favoriteFile == evt.srcElement.dataFile) {
        clonedElement.querySelector(".favorite").classList.toggle("hideFavorite");
      }
    }

    clonedElement.querySelector(".releaseValue").innerText = buildData.builds[0].build.releaseScore;
    clonedElement.querySelector(".hours").innerText = buildData.builds[0].build.hours;
    clonedElement.querySelector(".hotbugs").innerText = buildData.builds[0].build.hotbugs;
    clonedElement.querySelector(".triage").innerText = buildData.builds[0].build.triage;
    clonedElement.querySelector(".warnings").innerText = buildData.builds[0].build.warnings;
    clonedElement.querySelector(".arch").innerText = buildData.builds[0].build.platform;
    clonedElement.querySelector(".passrate").innerText = buildData.builds[0].build.passrate;

    //
    // NOTE: We don't want to send the entire JSON file again. We only
    //       need to send the parsed data. This is a TODO item that
    //       hasn't been addressed yet.
    //
    //if (detailedView == true) {
      createBarChart(clonedElement.querySelector(".chart"), evt.srcElement.dataFile);
    //}
    contentElement.appendChild(clonedElement);

    setupFavoritesEvents();

    // if (window.location.pathname == "/summaryPage.htm") {
    //   setupCarousel();
    // }

    //updateFavoriteStars();
}

function displayFavorites() {
  var favoritesArray;

  if (localStorage.getItem("favorites")) {
    favoritesArray = JSON.parse(localStorage.getItem("favorites"));
    processData(favoritesArray);
  } else {
    console.log("No Favorites!");
  }
}

//
// We want to visually differentiate builds you've favorited
// from builds you have not favorited
//
function updateFavoriteStars() {
  var favoritesArray;

  if (localStorage.getItem("favorites")) {
    favoritesArray = JSON.parse(localStorage.getItem("favorites"));

    for (var i = 0; i < favoritesArray.length; i++) {
      var favoriteFile = favoritesArray[i];
      var favoriteStar = document.querySelector(".favorite[data-file='" + favoriteFile + "']");
      favoriteStar.classList.toggle("hideFavorite");
    }
  }
}

var currentItem = 0;
var items;

var container = document.querySelector("#content");

//carousel sript
if(document.getElementById('dataViews')) {
var dataviews = document.getElementById('dataViewWrapper');

var changeFactor = function(dir){
    var currentValue = Number(dataviews.getAttribute('data-datapos'));

 if(dir === "lower") {

  dataviews.setAttribute('data-datapos', (currentValue === 0?0:currentValue-1))
 }else{

  dataviews.setAttribute('data-datapos', (currentValue === 4?4:currentValue+1))

 }

}

///listeners
document.getElementById('left').addEventListener('click', function(){
  changeFactor('lower')
})
document.getElementById('right').addEventListener('click', function(){
  changeFactor('higher')
})

var mode = 'system';
function modeSwitch(ev) {

    mode = ev.target.displayText;
}
if (typeof Windows != 'undefined') {

    // Modify System Defaults to Only Show Volume and Next/Prev Track as per guidance.
    // https://docs.microsoft.com/en-us/windows/uwp/input-and-devices/windows-wheel-interactions

    //initilize dial
    var config = Windows.UI.Input.RadialControllerConfiguration.getForCurrentView();
    config.setDefaultMenuItems([Windows.UI.Input.RadialControllerSystemMenuItemKind.scroll]);
    var controller = Windows.UI.Input.RadialController.createForCurrentView();

    // Add our own item to respond to
    // var mi = Windows.UI.Input.RadialControllerMenuItem.createFromKnownIcon("Undo/Redo", Windows.UI.Input.RadialControllerMenuKnownIcon.undoRedo);
    // mi.addEventListener("invoked", modeSwitch);

    // Add two custom sections for the dial interface
    // If images do not show on Dial, change path to be absolute
    var mi2 = Windows.UI.Input.RadialControllerMenuItem.createFromIcon("Review Builds", Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(new Windows.Foundation.Uri("https://es-tracker.azurewebsites.net/images/dial2.png")));
    var mi3 = Windows.UI.Input.RadialControllerMenuItem.createFromIcon("Release", Windows.Storage.Streams.RandomAccessStreamReference.createFromUri(new Windows.Foundation.Uri("https://es-tracker.azurewebsites.net/images/dial1.png")));
  //push to controler
    controller.menu.items.push(mi2);
    controller.menu.items.push(mi3);

    mi2.addEventListener("invoked", modeSwitch);
    mi3.addEventListener('invoked', modeSwitch);
  //  controller.menu.items.push(mi);

    controller.addEventListener("buttonclicked", function (e) {
     if(mode !== 'Release') return
     document.body.classList.toggle('build');
    });

    controller.addEventListener("rotationchanged", function (e) {
        if(mode !== 'Review Builds') return
        var changeDirection = e.detail[0].rotationDeltaInDegrees;
      if(changeDirection < 0){
        changeFactor('lower')
      }else{
        changeFactor('higher')

      }

      //  log("rotation changed: " + e.detail[0].rotationDeltaInDegrees + " in " + mode);
    });

}

//
///brb code

document.querySelector('.cancelbrb').addEventListener('click', function(){
  document.querySelector('#modal').classList.toggle('hidden')
})

setTimeout(function(){
var sendbuttons = document.querySelectorAll('.sendBuild');

for(var i = 0; i < sendbuttons.length;i++){
sendbuttons[i].addEventListener('click', function(){
    document.querySelector('#modal').classList.toggle('hidden')
})

}

}, 2000)
//
//
//
//
//
//
//
//
//
//
//
//
//
//
 }//end check for last page
<|endoftext|>