<commit_before>/* @flow */
/*
---
id: objects
title: Objects
permalink: /docs/objects.html
prev: classes.html
next: functions.html
---
*/

/*
Objects can be created with object literals. The types of properties are fixed
based on their initializers.
*/

// @flow
var o = {
  x: 42,
  foo(x) { this.x = x; }
};
// $ExpectError
o.foo('hello');

/*
Flow infers the type of property `x` of the object to be number since it is
initialized with a `number`. The method call `foo()` on the object writes
`string` to that property. As expected, running Flow produces an error.

## Object Types

Object types are of the form:

{% highlight javascript %}
{ x1: T1; x2: T2; x3: T3;}
{% endhighlight %}

Here is an example of declaring an object type:
*/

// @flow
class Foo {}
var obj: {a: boolean; b: string; c: Foo} = {a: true, b: "Hi", c: new Foo()}

/*
Here is an example of Flow catching a problem with your object type:
*/

// @flow
class Bar {}
// $ExpectError
var badObj: {a: boolean; b: string; c: Foo} = {a: true, b: "Hi", c: new Bar()}

/*
## Reusable Object Types

Object types can be made reusable through the use of
[type aliases](type-aliases.html):
*/

// @flow
type MyType = {message: string; isAwesome: boolean};
function sayHello(data: MyType) {
  console.log(data.message);
}

var mySampleData: MyType = {message: 'Hello World', isAwesome: true};
sayHello(mySampleData);
sayHello({message: 'Hi', isAwesome: false});

/*
## Optional properties

Object types can have optional properties. The following code shows how
optional properties allow objects with missing properties to be typed.
*/

// @flow
var optObj: { a: string; b?: number } = { a: "hello" };

/*
When optional properties are accessed, Flow tracks the fact that they could
be `undefined`, and reports errors when they are used as is.
*/

// $ExpectError
optObj.b * 10 // error: undefined is incompatible with number

/*
One way to avoid errors is to dynamically check that an optional property exists
before using it. See [nullable types](http://flowtype.org/docs/nullable-types.html#_) for details.

## Constructor Functions and Prototype Objects

Another way of creating objects in JavaScript is by using `new` on
constructor functions. A constructor function is typically an open method
that "initializes" some properties of `this`; and a `new` operation on such a
function calls it on a freshly created object before returning it.

Additionally, a constructor function may set various properties on its
`prototype` object. These properties are typically methods, and are inherited
by all objects created from that constructor function by a process known as
prototype chaining.
*/

// $WithLineNums
// @flow
function FuncBasedClass(x) { this.x = x; }
FuncBasedClass.prototype.f = function() { return this.x; }

var y = new FuncBasedClass(42);
var z: number = y.f();

/*
In this code, a `new` object is created by `new Foo(42)`; this object has a
property `x` initialized by `Foo` with the `number` passed to it. The object
also responds to the `f` method defined in `Foo.prototype`, so `o.f()` reads
`o.x` and returns it. This fits with the expectation of a `number` as
expressed by the annotation at line 6, so this code typechecks.

Furthermore, Flow ensures that an object's type can always be viewed as a
subtype of its constructor's `prototype type`. (This is analogous to subtyping
based on class inheritance.) This means that the following code typechecks:
*/

var anObj: FuncBasedClass = new FuncBasedClass(42);

/*
## Adding properties

It is a common idiom in JavaScript to add properties to objects after they are
created. In fact, we have already seen this idiom on several occasions above:
when initializing properties of `this` properties in a constructor function;
when building a constructor function's `prototype` object; when building a
`module.exports` object; and so on.

Flow supports this idiom. As far as we know, this is a type system novelty:
supporting this idiom while balancing other constraints of the type system,
such as sound subtyping over objects and prototypes, can be quite tricky!

However, for a property that may be added to an object after its creation,
Flow cannot guarantee the existence of that property at a particular property
access operation; it can only check that its writes and reads are type-
consistent. Providing such guarantees for dynamic objects would significantly
complicate the analysis; this is a well-known fact (in technical terms, Flow's
analysis is heap-insensitive for strong updates).

For example, the following code typechecks:
*/

// @flow
function foo(p) { p.x = 42; }
function bar(q) { q.f(); }

var o = { };
o.f = function() { return this.x; };

bar(o);
foo(o);

/*
In this code, when `bar(o)` is called, `o.x` is undefined; only later is it
initialized by `foo(o)`, but it is hard to track this fact statically.

Fortunately, though, the following code does not typecheck:
*/

foo(o);
// $ExpectError
var x: string = bar(o);

/*
In other words, Flow knows enough to infer that whenever the `x` property of
`o` does exist, it is a number, so a `string` should not be expected.

## Sealed object types

Unfortunately, supporting dynamically added properties means that Flow can miss
errors where the programmer accesses a non-existent property by mistake. Thus, Flow
also supports sealed object types, where accesses of non-existent properties are reported
as errors.

When object types appear as annotatations, they are considered sealed. Also, non-empty
object literals are considered to have sealed object types. In fact, the only cases where
an object type is not sealed are when it describes an empty object literal (to be extended
by adding properties to it), an object literal with [spread properties](https://github.com/sebmarkbage/ecmascript-rest-spread), or when it describes a map (see below).

Overall, the weaker guarantee for dynamically added properties is a small cost
to pay for the huge increase in flexibility it affords. Specifically, it
allows Flow to usefully type check lots of idiomatic JavaScript code, while
trusting the programmer to follow the discipline of fully initializing an
object before making it available, which effectively ensures that any
dynamically added properties during initialization are only accessed after
initialization is complete.

In any case, for most objects you can altogether avoid adding properties
dynamically, in which case you get stronger guarantees. Furthermore, as
described above, object type annotations are sealed, so you can always force
sealing by going through an annotation (and sealing is enforced at module
boundaries).

## Objects as Maps

An object can be viewed as a map from `string` to some value type by setting and
getting its properties via bracket notation (i.e. dynamic accessors), instead of
dot notation. Flow infers a precise value type for the map: in other words, if
you only write `number` values to a map, you will read `number` values back
(rather than, say, `any`).

Such a map can be given a type of the form `{ [key: string]: number }` where
`string` is the key type and `number` is the value type of the map.

### Maps as Records

Viewing an object as a map does not preclude viewing it as a record. However,
for such an object, the value type of the map does not interfere with the
types of the properties of the record. This is potentially unsound, but we
admit it because a sound design would necessarily lead to severe imprecision
in the types of properties.

### The `Object` type

This type describes "any object" and you can think of it like an
`any`-flavored version of an object type.

In JavaScript, everything is an object. Flow is a bit stricter and does not
consider primitive types to be subtypes of `Object`.)
*/

// $ExpectError
(0: Object);
// $ExpectError
("": Object);
// $ExpectError
(true: Object);
// $ExpectError
(null: Object);
// $ExpectError
(undefined: Object);

/*
Many other types can be treated as objects, however. Naturally objects are
compatible with `Object`, but so are functions and classes.
*/

({foo: "foo"}: Object);
(function() {}: Object);
(class {}: Object);
// $ExpectError
([]: Object); // Flow does not treat arrays as objects (likely to change)
<commit_msg>[Easy][Docs] Fix object example that had error for wrong reason<commit_after>/* @flow */
/*
---
id: objects
title: Objects
permalink: /docs/objects.html
prev: classes.html
next: functions.html
---
*/

/*
Objects can be created with object literals. The types of properties are fixed
based on their initializers.
*/

// @flow
var o = {
  x: 42,
  foo(x) { this.x = x; }
};
// $ExpectError
o.foo('hello');

/*
Flow infers the type of property `x` of the object to be number since it is
initialized with a `number`. The method call `foo()` on the object writes
`string` to that property. As expected, running Flow produces an error.

## Object Types

Object types are of the form:

{% highlight javascript %}
{ x1: T1; x2: T2; x3: T3;}
{% endhighlight %}

Here is an example of declaring an object type:
*/

// @flow
class Foo {}
var obj: {a: boolean; b: string; c: Foo} = {a: true, b: "Hi", c: new Foo()}

/*
Here is an example of Flow catching a problem with your object type:
*/

// @flow
class Bar {}
// $ExpectError
var badObj: {a: boolean; b: string; c: Foo} = {a: true, b: "Hi", c: new Bar()}

/*
## Reusable Object Types

Object types can be made reusable through the use of
[type aliases](type-aliases.html):
*/

// @flow
type MyType = {message: string; isAwesome: boolean};
function sayHello(data: MyType) {
  console.log(data.message);
}

var mySampleData: MyType = {message: 'Hello World', isAwesome: true};
sayHello(mySampleData);
sayHello({message: 'Hi', isAwesome: false});

/*
## Optional properties

Object types can have optional properties. The following code shows how
optional properties allow objects with missing properties to be typed.
*/

// @flow
var optObj: { a: string; b?: number } = { a: "hello" };

/*
When optional properties are accessed, Flow tracks the fact that they could
be `undefined`, and reports errors when they are used as is.
*/

// $ExpectError
optObj.b * 10 // error: undefined is incompatible with number

/*
One way to avoid errors is to dynamically check that an optional property exists
before using it. See [nullable types](http://flowtype.org/docs/nullable-types.html#_) for details.

## Constructor Functions and Prototype Objects

Another way of creating objects in JavaScript is by using `new` on
constructor functions. A constructor function is typically an open method
that "initializes" some properties of `this`; and a `new` operation on such a
function calls it on a freshly created object before returning it.

Additionally, a constructor function may set various properties on its
`prototype` object. These properties are typically methods, and are inherited
by all objects created from that constructor function by a process known as
prototype chaining.
*/

// $WithLineNums
// @flow
function FuncBasedClass(x) { this.x = x; }
FuncBasedClass.prototype.f = function() { return this.x; }

var y = new FuncBasedClass(42);
var z: number = y.f();

/*
In this code, a `new` object is created by `new Foo(42)`; this object has a
property `x` initialized by `Foo` with the `number` passed to it. The object
also responds to the `f` method defined in `Foo.prototype`, so `o.f()` reads
`o.x` and returns it. This fits with the expectation of a `number` as
expressed by the annotation at line 6, so this code typechecks.

Furthermore, Flow ensures that an object's type can always be viewed as a
subtype of its constructor's `prototype type`. (This is analogous to subtyping
based on class inheritance.) This means that the following code typechecks:
*/

var anObj: FuncBasedClass = new FuncBasedClass(42);

/*
## Adding properties

It is a common idiom in JavaScript to add properties to objects after they are
created. In fact, we have already seen this idiom on several occasions above:
when initializing properties of `this` properties in a constructor function;
when building a constructor function's `prototype` object; when building a
`module.exports` object; and so on.

Flow supports this idiom. As far as we know, this is a type system novelty:
supporting this idiom while balancing other constraints of the type system,
such as sound subtyping over objects and prototypes, can be quite tricky!

However, for a property that may be added to an object after its creation,
Flow cannot guarantee the existence of that property at a particular property
access operation; it can only check that its writes and reads are type-
consistent. Providing such guarantees for dynamic objects would significantly
complicate the analysis; this is a well-known fact (in technical terms, Flow's
analysis is heap-insensitive for strong updates).

For example, the following code typechecks:
*/

// @flow
function foo(p) { p.x = 42; }
function bar(q) { return q.f(); }

var o = { };
o.f = function() { return this.x; };

bar(o);
foo(o);

/*
In this code, when `bar(o)` is called, `o.x` is undefined; only later is it
initialized by `foo(o)`, but it is hard to track this fact statically.

Fortunately, though, the following code does not typecheck:
*/

// $ExpectError
var test: string = bar(o);

/*
In other words, Flow knows enough to infer that whenever the `x` property of
`o` does exist, it is a number, so a `string` should not be expected.

## Sealed object types

Unfortunately, supporting dynamically added properties means that Flow can miss
errors where the programmer accesses a non-existent property by mistake. Thus, Flow
also supports sealed object types, where accesses of non-existent properties are reported
as errors.

When object types appear as annotatations, they are considered sealed. Also, non-empty
object literals are considered to have sealed object types. In fact, the only cases where
an object type is not sealed are when it describes an empty object literal (to be extended
by adding properties to it), an object literal with [spread properties](https://github.com/sebmarkbage/ecmascript-rest-spread), or when it describes a map (see below).

Overall, the weaker guarantee for dynamically added properties is a small cost
to pay for the huge increase in flexibility it affords. Specifically, it
allows Flow to usefully type check lots of idiomatic JavaScript code, while
trusting the programmer to follow the discipline of fully initializing an
object before making it available, which effectively ensures that any
dynamically added properties during initialization are only accessed after
initialization is complete.

In any case, for most objects you can altogether avoid adding properties
dynamically, in which case you get stronger guarantees. Furthermore, as
described above, object type annotations are sealed, so you can always force
sealing by going through an annotation (and sealing is enforced at module
boundaries).

## Objects as Maps

An object can be viewed as a map from `string` to some value type by setting and
getting its properties via bracket notation (i.e. dynamic accessors), instead of
dot notation. Flow infers a precise value type for the map: in other words, if
you only write `number` values to a map, you will read `number` values back
(rather than, say, `any`).

Such a map can be given a type of the form `{ [key: string]: number }` where
`string` is the key type and `number` is the value type of the map.

### Maps as Records

Viewing an object as a map does not preclude viewing it as a record. However,
for such an object, the value type of the map does not interfere with the
types of the properties of the record. This is potentially unsound, but we
admit it because a sound design would necessarily lead to severe imprecision
in the types of properties.

### The `Object` type

This type describes "any object" and you can think of it like an
`any`-flavored version of an object type.

In JavaScript, everything is an object. Flow is a bit stricter and does not
consider primitive types to be subtypes of `Object`.)
*/

// $ExpectError
(0: Object);
// $ExpectError
("": Object);
// $ExpectError
(true: Object);
// $ExpectError
(null: Object);
// $ExpectError
(undefined: Object);

/*
Many other types can be treated as objects, however. Naturally objects are
compatible with `Object`, but so are functions and classes.
*/

({foo: "foo"}: Object);
(function() {}: Object);
(class {}: Object);
// $ExpectError
([]: Object); // Flow does not treat arrays as objects (likely to change)
<|endoftext|>


<commit_before>'use strict';

import { REQUEST_TIMEOUT } from '../lib/constants';
import { default as baseRequest } from 'request';
import _ from 'lodash';
import { default as moment } from 'moment-timezone';
import parallelLimit from 'async/parallelLimit';
import Bottleneck from 'bottleneck';
import { unifyMeasurementUnits } from '../lib/utils';
const request = baseRequest.defaults({timeout: REQUEST_TIMEOUT});

// Default rate limiting on API is set to 5 requests/sec.
// > Please send an email to Tools.support@epa.vic.gov.au with subject
// > 'EPA API Access Request: Increase rate-limiting' and a justified
// > reason if you want to get it increased for your subscriptions.
var maxRequestsPerSecond = 5;
var limiter = new Bottleneck({
  reservoir: maxRequestsPerSecond, // allow 5 requests
  reservoirRefreshAmount: maxRequestsPerSecond,
  reservoirRefreshInterval: 1000, // every 1000ms
  maxConcurrent: 1,
  minTime: (1000 / maxRequestsPerSecond) + 50 // to stagger requests out throught each second adding a 50ms buffer
});

export const name = 'victoria';

export function fetchData (source, cb) {
  limiter.submit(request, {
    url: source.url,
    headers: {
      'X-API-Key': process.env.EPA_VIC_TOKEN
    }
  }, function (err, res, body) {
    if (err || res.statusCode !== 200) {
      return cb({message: 'Failure to load data url.'});
    }

    // Wrap everything in a try/catch in case something goes wrong
    try {
      // Format the data
      formatData(body, function (err, data) {
        // Make sure the data is valid
        if (err || data === undefined) {
          return cb({message: 'Failure to parse data.'});
        }
        cb(null, data);
      });
    } catch (e) {
      return cb({message: 'Unknown adapter error.'});
    }
  });
}

var parameters = {
  'PM2.5': 'pm25',
  'PM10': 'pm10',
  'NO2': 'no2',
  'SO2': 'so2',
  'O3': 'o3',
  'CO': 'co',
  'BC': 'bc'
};

var units = {
  'µg/m³': 'µg/m³',
  'ppm': 'ppm',
  'ppb': 'ppb'
};

var formatData = function (data, formatDataCB) {
  var sites = JSON.parse(data).records;

  // request measurements from each site
  var tasks = sites.map(function (site) {
    return function (cb) {
      limiter.submit(request, {
        url: `https://gateway.api.epa.vic.gov.au/environmentMonitoring/v1/sites/${site.siteID}/parameters`,
        headers: {
          'X-API-Key': process.env.EPA_VIC_TOKEN
        }
      }, function (err, res, body) {
        if (err || res.statusCode !== 200) {
          console.error(err, res);
          return cb({message: 'Failure to load data url.'});
        }
        var source = JSON.parse(body);

        // base properties shared for all measurements at this site
        var baseProperties = {
          location: source.siteName,
          city: 'Victoria',
          country: 'AU',
          sourceName: source.name,
          sourceType: 'government',
          attribution: [{
            name: 'EPA Victoria State Government of Victoria',
            url: 'https://www.epa.vic.gov.au/EPAAirWatch'
          }],
          coordinates: {
            latitude: source.geometry.coordinates[0],
            longitude: source.geometry.coordinates[1]
          }
        };

        // list of all measurements at this site
        var measurements = [];
        if (source && source.parameters) {
          measurements = source.parameters.map(function (parameter) {
            if (parameter.name in parameters) {
              var measurement = _.cloneDeep(baseProperties);
              measurement.parameter = parameters[parameter.name];

              // from the range of time series readings, find the 1HR_AV one
              var averageReadings = parameter.timeSeriesReadings.filter(function (timeSeriesReading) {
                return timeSeriesReading.timeSeriesName === '1HR_AV';
              });

              if (averageReadings.length && averageReadings[0].readings.length) {
                var reading = averageReadings[0].readings[0];
                if (reading.unit in units) {
                  measurement.unit = units[reading.unit];
                  measurement.averagingPeriod = { value: 1, unit: 'hours' };
                  measurement.value = Number(reading.averageValue);

                  var date = moment.tz(reading.until, 'Australia/Melbourne');

                  measurement.date = {
                    utc: date.toDate(),
                    local: date.format()
                  };

                  return unifyMeasurementUnits(measurement);
                }
              }
            }
          }).filter(function (measurement) {
            return measurement !== null;
          });
        }

        cb(null, measurements);
      });
    };
  });

  parallelLimit(tasks, 1, function (err, measurements) {
    formatDataCB(err, {name: 'unused', measurements: _.flatten(measurements)});
  });
};
<commit_msg>hardcode cities<commit_after>'use strict';

import { REQUEST_TIMEOUT } from '../lib/constants';
import { default as baseRequest } from 'request';
import _ from 'lodash';
import { default as moment } from 'moment-timezone';
import parallelLimit from 'async/parallelLimit';
import Bottleneck from 'bottleneck';
import { unifyMeasurementUnits } from '../lib/utils';
const request = baseRequest.defaults({timeout: REQUEST_TIMEOUT});

// Default rate limiting on API is set to 5 requests/sec.
// > Please send an email to Tools.support@epa.vic.gov.au with subject
// > 'EPA API Access Request: Increase rate-limiting' and a justified
// > reason if you want to get it increased for your subscriptions.
var maxRequestsPerSecond = 5;
var limiter = new Bottleneck({
  reservoir: maxRequestsPerSecond, // allow 5 requests
  reservoirRefreshAmount: maxRequestsPerSecond,
  reservoirRefreshInterval: 1000, // every 1000ms
  maxConcurrent: 1,
  minTime: (1000 / maxRequestsPerSecond) + 50 // to stagger requests out throught each second adding a 50ms buffer
});

export const name = 'victoria';

export function fetchData (source, cb) {
  limiter.submit(request, {
    url: source.url,
    headers: {
      'X-API-Key': process.env.EPA_VIC_TOKEN
    }
  }, function (err, res, body) {
    if (err || res.statusCode !== 200) {
      return cb({message: 'Failure to load data url.'});
    }

    // Wrap everything in a try/catch in case something goes wrong
    try {
      // Format the data
      formatData(body, function (err, data) {
        // Make sure the data is valid
        if (err || data === undefined) {
          return cb({message: 'Failure to parse data.'});
        }
        cb(null, data);
      });
    } catch (e) {
      return cb({message: 'Unknown adapter error.'});
    }
  });
}

var parameters = {
  'PM2.5': 'pm25',
  'PM10': 'pm10',
  'NO2': 'no2',
  'SO2': 'so2',
  'O3': 'o3',
  'CO': 'co',
  'BC': 'bc'
};

var units = {
  'µg/m³': 'µg/m³',
  'ppm': 'ppm',
  'ppb': 'ppb'
};

// hardcoded mapping of location name -> city
var cities = {
  'Coolaroo': 'Melbourne',
  'Dallas': 'Melbourne',
  'Macleod': 'Melbourne',
  'Alphington': 'Melbourne',
  'Footscray': 'Melbourne',
  'Brooklyn': 'Melbourne',
  'Melbourne CBD': 'Melbourne',
  'Box Hill': 'Melbourne',
  'Brighton': 'Melbourne',
  'Dandenong': 'Melbourne',
  'Mooroolbark': 'Melbourne',
  'Geelong South': 'Geelong',
  'Morwell South': 'Morwell',
  'Morwell East': 'Morwell'
};

var formatData = function (data, formatDataCB) {
  var sites = JSON.parse(data).records;

  // request measurements from each site
  var tasks = sites.map(function (site) {
    return function (cb) {
      limiter.submit(request, {
        url: `https://gateway.api.epa.vic.gov.au/environmentMonitoring/v1/sites/${site.siteID}/parameters`,
        headers: {
          'X-API-Key': process.env.EPA_VIC_TOKEN
        }
      }, function (err, res, body) {
        if (err || res.statusCode !== 200) {
          console.error(err, res);
          return cb({message: 'Failure to load data url.'});
        }
        var source = JSON.parse(body);

        // base properties shared for all measurements at this site
        var baseProperties = {
          location: source.siteName,
          city: cities[source.siteName] || source.siteName,
          country: 'AU',
          sourceName: source.name,
          sourceType: 'government',
          attribution: [{
            name: 'EPA Victoria State Government of Victoria',
            url: 'https://www.epa.vic.gov.au/EPAAirWatch'
          }],
          coordinates: {
            latitude: source.geometry.coordinates[0],
            longitude: source.geometry.coordinates[1]
          }
        };

        // list of all measurements at this site
        var measurements = [];
        if (source && source.parameters) {
          measurements = source.parameters.map(function (parameter) {
            if (parameter.name in parameters) {
              var measurement = _.cloneDeep(baseProperties);
              measurement.parameter = parameters[parameter.name];

              // from the range of time series readings, find the 1HR_AV one
              var averageReadings = parameter.timeSeriesReadings.filter(function (timeSeriesReading) {
                return timeSeriesReading.timeSeriesName === '1HR_AV';
              });

              if (averageReadings.length && averageReadings[0].readings.length) {
                var reading = averageReadings[0].readings[0];
                if (reading.unit in units) {
                  measurement.unit = units[reading.unit];
                  measurement.averagingPeriod = { value: 1, unit: 'hours' };
                  measurement.value = Number(reading.averageValue);

                  var date = moment.tz(reading.until, 'Australia/Melbourne');

                  measurement.date = {
                    utc: date.toDate(),
                    local: date.format()
                  };

                  return unifyMeasurementUnits(measurement);
                }
              }
            }
          }).filter(function (measurement) {
            return measurement !== null;
          });
        }

        cb(null, measurements);
      });
    };
  });

  parallelLimit(tasks, 1, function (err, measurements) {
    formatDataCB(err, {name: 'unused', measurements: _.flatten(measurements)});
  });
};
<|endoftext|>


<commit_before>///server/boot/autoupdate.js
module.exports = function(app) {
    var path = require('path');
    var models = require(path.resolve(__dirname, '../model-config.json'));
    var datasources = require(path.resolve(__dirname, '../datasources.json'));

    function autoUpdateAll(){
        Object.keys(models).forEach(function(key) {
            if (typeof models[key].dataSource != 'undefined') {
                if (typeof datasources[models[key].dataSource] != 'undefined') {
                    app.dataSources[models[key].dataSource].autoupdate(key, function (err) {
                        if (err) throw err;
                        console.log('Model ' + key + ' updated');
                    });
                }
            }
        });
    }

    function autoMigrateAll(){
        Object.keys(models).forEach(function(key) {
            if (typeof models[key].dataSource != 'undefined') {
                if (typeof datasources[models[key].dataSource] != 'undefined') {
                    app.dataSources[models[key].dataSource].automigrate(key, function (err) {
                        if (err) throw err;
                        console.log('Model ' + key + ' migrated');
                    });
                }
            }
        });
    }
    autoMigrateAll();
    //autoUpdateAll();

};
<commit_msg>from now on keep data in place when migrating<commit_after>///server/boot/autoupdate.js
module.exports = function(app) {
    var path = require('path');
    var models = require(path.resolve(__dirname, '../model-config.json'));
    var datasources = require(path.resolve(__dirname, '../datasources.json'));

    function autoUpdateAll(){
        Object.keys(models).forEach(function(key) {
            if (typeof models[key].dataSource != 'undefined') {
                if (typeof datasources[models[key].dataSource] != 'undefined') {
                    app.dataSources[models[key].dataSource].autoupdate(key, function (err) {
                        if (err) throw err;
                        console.log('Model ' + key + ' updated');
                    });
                }
            }
        });
    }

    function autoMigrateAll(){
        Object.keys(models).forEach(function(key) {
            if (typeof models[key].dataSource != 'undefined') {
                if (typeof datasources[models[key].dataSource] != 'undefined') {
                    app.dataSources[models[key].dataSource].automigrate(key, function (err) {
                        if (err) throw err;
                        console.log('Model ' + key + ' migrated');
                    });
                }
            }
        });
    }
    //autoMigrateAll();
    autoUpdateAll();

};
<|endoftext|>


<commit_before>/**
 * csv.js - an experiment in parse CSV content.
 * @author R. S. Doiel, <rsdoiel@gmail.com>
 * copyright (c) 2013 all rights reserved
 * Released under the BSD 2-clause licensed.
 * See: http://opensource.org/licenses/BSD-2-Clause
 */
/*jslint browser: true, indent: 4 */
/*global console, modules */
(function () {
    "use strict";

    function parseLine(buf) {
        var delimiter = ',',
            escape = '\\',
            eol = '\n',
            quote = '',
            cut_from = 0,
            cur = '',
            i = 0,
            l = 0,
            results = [];

        function saveColumn(s) {
            var l;
            s = s.trim();
            l = s.length - 1;
            if ((s[0] === '"' && s[l] === '"') ||
                    (s[0] === "'" && s[l] === "'")) {
                // We have a quoted string so remove/unescape any quotes
                // based on s[0]
                s = s.substr(1, s.length - 2).replace(new RegExp(escape + escape + s[0], 'g'), s[0]);
            }
            return s;
        }

        for (i = 0, l = buf.length, cut_from = 0; i < l; i += 1) {
            cur = buf[i];
            if (cur === delimiter && quote === '') {
                // save the column's data
                results.push(saveColumn(buf.substr(cut_from, i - cut_from)));
                cut_from = i + 1;
                quote = '';
            } else if (cur === escape) {
                i += 1;
            } else if ((cur === '"' || cur === "'") && quote === '') {
                // Starting of a quote
                quote = cur;
            } else if (cur === quote && quote !== "") {
                // Ending of a quote
                quote = '';
            }
        }
        // get last column
        if (cut_from <= l) {
            results.push(saveColumn(buf.substr(cut_from), l - cut_from));
        }
        return results;
    }
    // Export as module
    modules("CSV", {parseLine: parseLine});
}());
<commit_msg>Update csv.js<commit_after>/**
 * csv.js - an experiment in parse CSV content.
 * @author R. S. Doiel, <rsdoiel@gmail.com>
 * copyright (c) 2013 all rights reserved
 * Released under the BSD 2-clause licensed.
 * See: http://opensource.org/licenses/BSD-2-Clause
 */
/*jslint browser: true, indent: 4 */
/*global console, modules */
(function () {
    "use strict";

    function saveColumn(s) {
        var l;
        s = s.trim();
        l = s.length - 1;
        if ((s[0] === '"' && s[l] === '"') ||
            (s[0] === "'" && s[l] === "'")) {
          // We have a quoted string so remove/unescape any quotes
          // based on s[0]
          s = s.substr(1, s.length - 2).replace(new RegExp(escape + escape + s[0], 'g'), s[0]);
        }
        return s;
    }

    function parseLine(buf) {
        var delimiter = ',',
            escape = '\\',
            eol = '\n',
            quote = '',
            cut_from = 0,
            cur = '',
            i = 0,
            l = buf.length,
            i_eof = l - 1,
            columns = [];

        for (i = 0; i < l; i += 1) {
            cur = buf[i];
            if (((cur === delimiter || cur === eol) && quote === '') ||
                     i === i_eof) {
                // save the column's data
                columns.push(saveColumn(buf.substr(cut_from, i - cut_from)));
                cut_from = i + 1;
                quote = '';
            } else if (cur === escape) {
                i += 1;
            } else if ((cur === '"' || cur === "'") && quote === '') {
                // Starting of a quote
                quote = cur;
            } else if (cur === quote && quote !== "") {
                // Ending of a quote
                quote = '';
            }
        }
        return columns;
    }

    function parse(buf) {
        var delimiter = ',',
            escape = '\\',
            eol = '\n',
            quote = '',
            cut_from = 0,
            cur = '',
            i = 0,
            l = buf.length,
            i_eof = l - 1,
            columns = [],
            rows = [];

        for (i = 0; i < l; i += 1) {
            cur = buf[i];
            if (((cur === delimiter || cur === eol) && quote === '') ||
                     i === i_eof) {
                // save the column's data
                columns.push(saveColumn(buf.substr(cut_from, i - cut_from)));
                cut_from = i + 1;
                quote = '';
                if (cur === eol || i == i_eof) {
                    rows.push(columns);
                    columns = [];
                }
            } else if (cur === escape) {
                i += 1;
            } else if ((cur === '"' || cur === "'") && quote === '') {
                // Starting of a quote
                quote = cur;
            } else if (cur === quote && quote !== "") {
                // Ending of a quote
                quote = '';
            }
        }
        return rows;
    }

    // Export as module
    modules("CSV", {
      parseLine: parseLine,
      parse: parse
    });
}());
<|endoftext|>


<commit_before>import fuzzysearch from 'fuzzysearch';
import blueslip from './../blueslip';

import { path_parts } from './landing-page';

// these constants are populated immediately with data from the DOM on page load
// name -> display name
var INTEGRATIONS = {};
var CATEGORIES = {};

function load_data() {
    $('.integration-lozenge').toArray().forEach(function (integration) {
        var name = $(integration).data('name');
        var display_name = $(integration).find('.integration-name').text().trim();

        if (display_name && name) {
            INTEGRATIONS[name] = display_name;
        }
    });

    $('.integration-category').toArray().forEach(function (category) {
        var name = $(category).data('category');
        var display_name = $(category).text().trim();

        if (display_name && name) {
            CATEGORIES[name] = display_name;
        }
    });
}

var INITIAL_STATE = {
    category: 'all',
    integration: null,
    query: '',
};

var state = Object.assign({}, INITIAL_STATE);

function adjust_font_sizing() {
    $('.integration-lozenge').toArray().forEach(function (integration) {
        var $integration_name = $(integration).find('.integration-name');
        var $integration_category = $(integration).find('.integration-category');

        // if the text has wrapped to two lines, decrease font-size
        if ($integration_name.height() > 30) {
            $integration_name.css('font-size', '1em');
            if ($integration_name.height() > 30) {
                 $integration_name.css('font-size', '.95em');
            }
        }

        if ($integration_category.height() > 30) {
            $integration_category.css('font-size', '.8em');
            if ($integration_category.height() > 30) {
                $integration_category.css('font-size', '.75em');
            }
        }
    });
}

function update_path() {
    var next_path;
    if (state.integration) {
        next_path = $('.integration-lozenge[data-name="' + state.integration + '"]')
            .closest('a').attr('href');
    } else if (state.category) {
        next_path = $('.integration-category[data-category="' + state.category + '"]')
            .closest('a').attr('href');
    } else {
        next_path = '/';
    }

    window.history.pushState(state, '', next_path);
}

function update_categories() {
    $('.integration-lozenges').css('opacity', 0);

    $('.integration-category').removeClass('selected');
    $('[data-category="' + state.category + '"]').addClass('selected');

    var $dropdown_label = $('.integration-categories-dropdown .dropdown-category-label');
    var $dropdown_icon = $('.integration-categories-dropdown i');
    if (state.category === INITIAL_STATE.category) {
        $dropdown_label.text(i18n.t('Filter by category'));
    } else {
        $dropdown_label.text(CATEGORIES[state.category]);
        $dropdown_icon
            .removeClass('icon-vector-angle-right')
            .addClass('icon-vector-angle-down');
    }

    $('.integration-lozenges').animate(
        { opacity: 1 },
        { duration: 400 }
    );
}

var update_integrations = _.debounce(function () {
    var max_scrollY = window.scrollY;

    var integrations = $('.integration-lozenges').children().toArray();
    integrations.forEach(function (integration) {
        var $integration = $(integration).find('.integration-lozenge');
        var $integration_category = $integration.find('.integration-category');

        if (state.category !== 'all') {
            $integration_category.css('display', 'none');
            $integration.addClass('without-category');
        } else {
            $integration_category.css('display', '');
            $integration.removeClass('without-category');
        }

        if (!$integration.hasClass('integration-create-your-own')) {
            var display =
                fuzzysearch(state.query, $integration.data('name').toLowerCase()) &&
                ($integration.data('categories').indexOf(CATEGORIES[state.category]) !== -1 ||
                 state.category === 'all');

            if (display) {
                $integration.css('display', 'inline-block');
            } else {
                $integration.css('display', 'none');
            }
        }

        document.body.scrollTop = Math.min(window.scrollY, max_scrollY);
    });
}, 50);

function hide_catalog_show_integration() {
    var $lozenge_icon = $(".integration-lozenge.integration-" + state.integration).clone(false);
    $lozenge_icon.removeClass('legacy');

    var categories = $('.integration-' + state.integration).data('categories')
        .slice(1, -1)
        .split(',')
        .map(function (category) {
            return category.trim().slice(1, -1);
        });

    function show_integration(doc) {
        $('#integration-instructions-group .name').text(INTEGRATIONS[state.integration]);
        $('#integration-instructions-group .categories .integration-category').remove();
        categories.forEach(function (category) {
            var link;
            Object.keys(CATEGORIES).forEach(function (name) {
                if (CATEGORIES[name] === category) {
                    link = name;
                }
            });
            var category_el = $('')
                .attr('href', '/integrations/' + link)
                .append('

');
            category_el.find('.integration-category')
                .attr('data-category', link)
                .text(category);
            $('#integration-instructions-group .categories').append(category_el);
        });
        $('#integration-instructions-group').css({
            opacity: 0,
            display: 'block',
        });
        $('.integration-instructions').css('display', 'none');
        $('#' + state.integration + '.integration-instructions .help-content').html(doc);
        $('#integration-instruction-block .integration-lozenge').remove();
        $("#integration-instruction-block")
            .append($lozenge_icon)
            .css('display', 'block');
        $('.integration-instructions#' + state.integration).css('display', 'block');
        $("#integration-list-link").css('display', 'block');

        $("html, body").animate(
            { scrollTop: 0 },
            { duration: 200 }
        );
        $('#integration-instructions-group').animate(
            { opacity: 1 },
            { duration: 300 }
        );
    }

    function hide_catalog(doc) {
        $(".integration-categories-dropdown").css('display', 'none');
        $(".integrations .catalog").addClass('hide');
        $(".extra, #integration-main-text, #integration-search").css("display", "none");

        show_integration(doc);
    }

    $.get({
        url: '/integrations/doc-html/' + state.integration,
        dataType: 'html',
        success: hide_catalog,
        error: function (err) {
            blueslip.error("Integration documentation for '" + state.integration + "' not found.", err);
        },
    });
}

function hide_integration_show_catalog() {
    function show_catalog() {
        $("html, body").animate(
            { scrollTop: 0 },
            { duration: 200 }
        );

        $(".integration-categories-dropdown").css('display', '');
        $(".integrations .catalog").removeClass('hide');
        $(".extra, #integration-main-text, #integration-search").css("display", "block");
    }

    function hide_integration() {
        $('#integration-instruction-block').css('display', 'none');
        $('#integration-instructions-group').css('display', 'none');
        $('.inner-content').css({ padding: '' });
        $("#integration-instruction-block .integration-lozenge").remove();
        show_catalog();
    }

    hide_integration();
}

function get_state_from_path() {
    var result = Object.assign({}, INITIAL_STATE);
    result.query = state.query;

    var parts = path_parts();
    if (parts[1] === 'doc' && INTEGRATIONS[parts[2]]) {
        result.integration = parts[2];
    } else if (CATEGORIES[parts[1]]) {
        result.category = parts[1];
    }

    return result;
}

function render(next_state) {
    var previous_state = Object.assign({}, state);
    state = next_state;

    if (previous_state.integration !== next_state.integration) {
        if (next_state.integration !== null) {
            hide_catalog_show_integration();
        } else {
            hide_integration_show_catalog();
        }
    }

    if (previous_state.category !== next_state.category) {
        update_categories();
        update_integrations();
    }

    if (previous_state.query !== next_state.query) {
        update_integrations();
    }
}

function dispatch(action, payload) {
    switch (action) {
        case 'CHANGE_CATEGORY':
            render(Object.assign({}, state, {
                category: payload.category,
            }));
            update_path();
            break;

        case 'SHOW_INTEGRATION':
            render(Object.assign({}, state, {
                integration: payload.integration,
            }));
            update_path();
            break;

        case 'HIDE_INTEGRATION':
            render(Object.assign({}, state, {
                integration: null,
            }));
            update_path();
            break;

        case 'SHOW_CATEGORY':
            render(Object.assign({}, state, {
                integration: null,
                category: payload.category,
            }));
            update_path();
            break;

        case 'UPDATE_QUERY':
            render(Object.assign({}, state, {
                query: payload.query,
            }));
            break;

        case 'LOAD_PATH':
            render(get_state_from_path());
            break;

        default:
            blueslip.error('Invalid action dispatched on /integrations.');
            break;
    }
}

function integration_events() {
    $('#integration-search input[type="text"]').keypress(function (e) {
        var integrations = $('.integration-lozenges').children().toArray();
        if (e.which === 13 && e.target.value !== '') {
            for (var i = 0; i < integrations.length; i += 1) {
                var integration = $(integrations[i]).find('.integration-lozenge');

                if ($(integration).css('display') !== 'none') {
                    $(integration).closest('a')[0].click();
                    break;
                }
            }
        }
    });

    $('.integration-categories-dropdown .dropdown-toggle').click(function () {
        var $dropdown_list = $('.integration-categories-dropdown .dropdown-list');
        $dropdown_list.toggle();

        if ($dropdown_list.css('display') === 'none' &&
            state.category === INITIAL_STATE.category) {
            $('.integration-categories-dropdown i')
                .removeClass('icon-vector-angle-down')
                .addClass('icon-vector-angle-right');
        } else {
            $('.integration-categories-dropdown i')
                .removeClass('icon-vector-angle-right')
                .addClass('icon-vector-angle-down');
        }
    });

    $('.integration-instruction-block').on('click', 'a .integration-category', function (e) {
        var category = $(e.target).data('category');
        dispatch('SHOW_CATEGORY', { category: category });
        return false;
    });

    $('.integrations a .integration-category').on('click', function (e) {
        var category = $(e.target).data('category');
        dispatch('CHANGE_CATEGORY', { category: category });
        return false;
    });

    $('.integrations a .integration-lozenge').on('click', function (e) {
        if (!$(e.target).closest('.integration-lozenge').hasClass('integration-create-your-own')) {
            var integration = $(e.target).closest('.integration-lozenge').data('name');
            dispatch('SHOW_INTEGRATION', { integration: integration });
            return false;
        }
    });

    $('a#integration-list-link span, a#integration-list-link i').on('click', function () {
        dispatch('HIDE_INTEGRATION');
        return false;
    });

    $(".integrations .searchbar input[type='text']").on('input', function (e) {
        dispatch('UPDATE_QUERY', { query : e.target.value.toLowerCase() });
    });

    $(window).scroll(function () {
        if (document.body.scrollTop > 330) {
            $('.integration-categories-sidebar').addClass('sticky');
        } else {
             $('.integration-categories-sidebar').removeClass('sticky');
        }
    });

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

    $(window).on('popstate', function () {
        if (window.location.pathname.startsWith('/integrations')) {
            dispatch('LOAD_PATH');
        } else {
            window.location = window.location.href;
        }
    });
}

// init
$(function () {
    integration_events();
    adjust_font_sizing();
    load_data();
    dispatch('LOAD_PATH');
});
<commit_msg>integration.js: Invoke adjust_font_sizing on all re-renders.<commit_after>import fuzzysearch from 'fuzzysearch';
import blueslip from './../blueslip';

import { path_parts } from './landing-page';

// these constants are populated immediately with data from the DOM on page load
// name -> display name
var INTEGRATIONS = {};
var CATEGORIES = {};

function load_data() {
    $('.integration-lozenge').toArray().forEach(function (integration) {
        var name = $(integration).data('name');
        var display_name = $(integration).find('.integration-name').text().trim();

        if (display_name && name) {
            INTEGRATIONS[name] = display_name;
        }
    });

    $('.integration-category').toArray().forEach(function (category) {
        var name = $(category).data('category');
        var display_name = $(category).text().trim();

        if (display_name && name) {
            CATEGORIES[name] = display_name;
        }
    });
}

var INITIAL_STATE = {
    category: 'all',
    integration: null,
    query: '',
};

var state = Object.assign({}, INITIAL_STATE);

function adjust_font_sizing() {
    $('.integration-lozenge').toArray().forEach(function (integration) {
        var $integration_name = $(integration).find('.integration-name');
        var $integration_category = $(integration).find('.integration-category');

        // if the text has wrapped to two lines, decrease font-size
        if ($integration_name.height() > 30) {
            $integration_name.css('font-size', '1em');
            if ($integration_name.height() > 30) {
                 $integration_name.css('font-size', '.95em');
            }
        }

        if ($integration_category.height() > 30) {
            $integration_category.css('font-size', '.8em');
            if ($integration_category.height() > 30) {
                $integration_category.css('font-size', '.75em');
            }
        }
    });
}

function update_path() {
    var next_path;
    if (state.integration) {
        next_path = $('.integration-lozenge[data-name="' + state.integration + '"]')
            .closest('a').attr('href');
    } else if (state.category) {
        next_path = $('.integration-category[data-category="' + state.category + '"]')
            .closest('a').attr('href');
    } else {
        next_path = '/';
    }

    window.history.pushState(state, '', next_path);
}

function update_categories() {
    $('.integration-lozenges').css('opacity', 0);

    $('.integration-category').removeClass('selected');
    $('[data-category="' + state.category + '"]').addClass('selected');

    var $dropdown_label = $('.integration-categories-dropdown .dropdown-category-label');
    var $dropdown_icon = $('.integration-categories-dropdown i');
    if (state.category === INITIAL_STATE.category) {
        $dropdown_label.text(i18n.t('Filter by category'));
    } else {
        $dropdown_label.text(CATEGORIES[state.category]);
        $dropdown_icon
            .removeClass('icon-vector-angle-right')
            .addClass('icon-vector-angle-down');
    }

    $('.integration-lozenges').animate(
        { opacity: 1 },
        { duration: 400 }
    );

    adjust_font_sizing();
}

var update_integrations = _.debounce(function () {
    var max_scrollY = window.scrollY;

    var integrations = $('.integration-lozenges').children().toArray();
    integrations.forEach(function (integration) {
        var $integration = $(integration).find('.integration-lozenge');
        var $integration_category = $integration.find('.integration-category');

        if (state.category !== 'all') {
            $integration_category.css('display', 'none');
            $integration.addClass('without-category');
        } else {
            $integration_category.css('display', '');
            $integration.removeClass('without-category');
        }

        if (!$integration.hasClass('integration-create-your-own')) {
            var display =
                fuzzysearch(state.query, $integration.data('name').toLowerCase()) &&
                ($integration.data('categories').indexOf(CATEGORIES[state.category]) !== -1 ||
                 state.category === 'all');

            if (display) {
                $integration.css('display', 'inline-block');
            } else {
                $integration.css('display', 'none');
            }
        }

        document.body.scrollTop = Math.min(window.scrollY, max_scrollY);
    });

    adjust_font_sizing();
}, 50);

function hide_catalog_show_integration() {
    var $lozenge_icon = $(".integration-lozenge.integration-" + state.integration).clone(false);
    $lozenge_icon.removeClass('legacy');

    var categories = $('.integration-' + state.integration).data('categories')
        .slice(1, -1)
        .split(',')
        .map(function (category) {
            return category.trim().slice(1, -1);
        });

    function show_integration(doc) {
        $('#integration-instructions-group .name').text(INTEGRATIONS[state.integration]);
        $('#integration-instructions-group .categories .integration-category').remove();
        categories.forEach(function (category) {
            var link;
            Object.keys(CATEGORIES).forEach(function (name) {
                if (CATEGORIES[name] === category) {
                    link = name;
                }
            });
            var category_el = $('')
                .attr('href', '/integrations/' + link)
                .append('

');
            category_el.find('.integration-category')
                .attr('data-category', link)
                .text(category);
            $('#integration-instructions-group .categories').append(category_el);
        });
        $('#integration-instructions-group').css({
            opacity: 0,
            display: 'block',
        });
        $('.integration-instructions').css('display', 'none');
        $('#' + state.integration + '.integration-instructions .help-content').html(doc);
        $('#integration-instruction-block .integration-lozenge').remove();
        $("#integration-instruction-block")
            .append($lozenge_icon)
            .css('display', 'block');
        $('.integration-instructions#' + state.integration).css('display', 'block');
        $("#integration-list-link").css('display', 'block');

        $("html, body").animate(
            { scrollTop: 0 },
            { duration: 200 }
        );
        $('#integration-instructions-group').animate(
            { opacity: 1 },
            { duration: 300 }
        );

        adjust_font_sizing();
    }

    function hide_catalog(doc) {
        $(".integration-categories-dropdown").css('display', 'none');
        $(".integrations .catalog").addClass('hide');
        $(".extra, #integration-main-text, #integration-search").css("display", "none");

        show_integration(doc);
    }

    $.get({
        url: '/integrations/doc-html/' + state.integration,
        dataType: 'html',
        success: hide_catalog,
        error: function (err) {
            blueslip.error("Integration documentation for '" + state.integration + "' not found.", err);
        },
    });
}

function hide_integration_show_catalog() {
    function show_catalog() {
        $("html, body").animate(
            { scrollTop: 0 },
            { duration: 200 }
        );

        $(".integration-categories-dropdown").css('display', '');
        $(".integrations .catalog").removeClass('hide');
        $(".extra, #integration-main-text, #integration-search").css("display", "block");
        adjust_font_sizing();
    }

    function hide_integration() {
        $('#integration-instruction-block').css('display', 'none');
        $('#integration-instructions-group').css('display', 'none');
        $('.inner-content').css({ padding: '' });
        $("#integration-instruction-block .integration-lozenge").remove();
        show_catalog();
    }

    hide_integration();
}

function get_state_from_path() {
    var result = Object.assign({}, INITIAL_STATE);
    result.query = state.query;

    var parts = path_parts();
    if (parts[1] === 'doc' && INTEGRATIONS[parts[2]]) {
        result.integration = parts[2];
    } else if (CATEGORIES[parts[1]]) {
        result.category = parts[1];
    }

    return result;
}

function render(next_state) {
    var previous_state = Object.assign({}, state);
    state = next_state;

    if (previous_state.integration !== next_state.integration) {
        if (next_state.integration !== null) {
            hide_catalog_show_integration();
        } else {
            hide_integration_show_catalog();
        }
    }

    if (previous_state.category !== next_state.category) {
        update_categories();
        update_integrations();
    }

    if (previous_state.query !== next_state.query) {
        update_integrations();
    }
}

function dispatch(action, payload) {
    switch (action) {
        case 'CHANGE_CATEGORY':
            render(Object.assign({}, state, {
                category: payload.category,
            }));
            update_path();
            break;

        case 'SHOW_INTEGRATION':
            render(Object.assign({}, state, {
                integration: payload.integration,
            }));
            update_path();
            break;

        case 'HIDE_INTEGRATION':
            render(Object.assign({}, state, {
                integration: null,
            }));
            update_path();
            break;

        case 'SHOW_CATEGORY':
            render(Object.assign({}, state, {
                integration: null,
                category: payload.category,
            }));
            update_path();
            break;

        case 'UPDATE_QUERY':
            render(Object.assign({}, state, {
                query: payload.query,
            }));
            break;

        case 'LOAD_PATH':
            render(get_state_from_path());
            break;

        default:
            blueslip.error('Invalid action dispatched on /integrations.');
            break;
    }
}

function integration_events() {
    $('#integration-search input[type="text"]').keypress(function (e) {
        var integrations = $('.integration-lozenges').children().toArray();
        if (e.which === 13 && e.target.value !== '') {
            for (var i = 0; i < integrations.length; i += 1) {
                var integration = $(integrations[i]).find('.integration-lozenge');

                if ($(integration).css('display') !== 'none') {
                    $(integration).closest('a')[0].click();
                    break;
                }
            }
        }
    });

    $('.integration-categories-dropdown .dropdown-toggle').click(function () {
        var $dropdown_list = $('.integration-categories-dropdown .dropdown-list');
        $dropdown_list.toggle();

        if ($dropdown_list.css('display') === 'none' &&
            state.category === INITIAL_STATE.category) {
            $('.integration-categories-dropdown i')
                .removeClass('icon-vector-angle-down')
                .addClass('icon-vector-angle-right');
        } else {
            $('.integration-categories-dropdown i')
                .removeClass('icon-vector-angle-right')
                .addClass('icon-vector-angle-down');
        }
    });

    $('.integration-instruction-block').on('click', 'a .integration-category', function (e) {
        var category = $(e.target).data('category');
        dispatch('SHOW_CATEGORY', { category: category });
        return false;
    });

    $('.integrations a .integration-category').on('click', function (e) {
        var category = $(e.target).data('category');
        dispatch('CHANGE_CATEGORY', { category: category });
        return false;
    });

    $('.integrations a .integration-lozenge').on('click', function (e) {
        if (!$(e.target).closest('.integration-lozenge').hasClass('integration-create-your-own')) {
            var integration = $(e.target).closest('.integration-lozenge').data('name');
            dispatch('SHOW_INTEGRATION', { integration: integration });
            return false;
        }
    });

    $('a#integration-list-link span, a#integration-list-link i').on('click', function () {
        dispatch('HIDE_INTEGRATION');
        return false;
    });

    $(".integrations .searchbar input[type='text']").on('input', function (e) {
        dispatch('UPDATE_QUERY', { query : e.target.value.toLowerCase() });
    });

    $(window).scroll(function () {
        if (document.body.scrollTop > 330) {
            $('.integration-categories-sidebar').addClass('sticky');
        } else {
             $('.integration-categories-sidebar').removeClass('sticky');
        }
    });

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

    $(window).on('popstate', function () {
        if (window.location.pathname.startsWith('/integrations')) {
            dispatch('LOAD_PATH');
        } else {
            window.location = window.location.href;
        }
    });
}

// init
$(function () {
    integration_events();
    load_data();
    dispatch('LOAD_PATH');
});
<|endoftext|>


<commit_before>/*eslint-env node */
var Cucumber = require('cucumber');
var assert = require('cucumber-assert');
var webdriver = require('selenium-webdriver');

Cucumber.defineSupportCode(function({setDefaultTimeout}) {
  setDefaultTimeout(60 * 1000);
});

Cucumber.defineSupportCode(function(context) {
  var When = context.When;
  var Then = context.Then;

  function createBrowserStackSession(config, caps){
    return new webdriver.Builder().
      usingServer('http://'+config.server+'/wd/hub').
      withCapabilities(caps).
      build();
  }

  var config = {
    server: 'hub-cloud.browserstack.com',
    capabilities: [{
      browserName: 'chrome',
      build: process.env.CIRCLE_BUILD_NUM,
      project: process.env.CIRCLE_PROJECT_REPONAME + '-' + process.env.CIRCLE_BRANCH,
      'browserstack.local': true
    }]
  };

  var task_id = parseInt(process.env.TASK_ID || 0, 10);
  var caps = config.capabilities[task_id];
  caps['browserstack.user'] = process.env.BS_USERNAME || config.user;
  caps['browserstack.key'] = process.env.BS_AUTHKEY || config.key;

  // Code to start browserstack local before start of test and stop browserstack local after end of test
  var browserstack = require("browserstack-local");
  var driver;
  bs_local = new browserstack.Local();
  bs_local.start({'key': caps['browserstack.key']}, function(error) {
    if (error) return console.log(error.red);
    driver = createBrowserStackSession(config, caps);
  });

  ///// Your step definitions /////
  //
  // use 'Given', 'When' and 'Then' to declare step definitions
  //

  When(/^I open site$/, function (next) {
    driver.get('http://127.0.0.1/').then(next);
  });

  Then(/^I should see title "([^"]*)"$/, function (titleMatch, next) {
    driver.getTitle()
      .then(function(title) {
        assert.equal(title, titleMatch, next, 'Expected title to be ' + titleMatch);
      });
  });

  driver.quit();

});
<commit_msg>Update browserstack-local.js<commit_after>/*eslint-env node */
var Cucumber = require('cucumber');
var assert = require('cucumber-assert');
var webdriver = require('selenium-webdriver');

Cucumber.defineSupportCode(function({setDefaultTimeout}) {
  setDefaultTimeout(60 * 1000);
});

Cucumber.defineSupportCode(function(context) {
  var When = context.When;
  var Then = context.Then;

  function createBrowserStackSession(config, caps){
    return new webdriver.Builder().
      usingServer('http://'+config.server+'/wd/hub').
      withCapabilities(caps).
      build();
  }

  var config = {
    server: 'hub-cloud.browserstack.com',
    capabilities: [{
      browserName: 'chrome',
      build: process.env.CIRCLE_BUILD_NUM,
      project: process.env.CIRCLE_PROJECT_REPONAME + '-' + process.env.CIRCLE_BRANCH,
      'browserstack.local': true
    }]
  };

  var task_id = parseInt(process.env.TASK_ID || 0, 10);
  var caps = config.capabilities[task_id];
  caps['browserstack.user'] = process.env.BS_USERNAME || config.user;
  caps['browserstack.key'] = process.env.BS_AUTHKEY || config.key;

  // Code to start browserstack local before start of test and stop browserstack local after end of test
  var browserstack = require("browserstack-local");
  var driver;
  bs_local = new browserstack.Local();
  bs_local.start({'key': caps['browserstack.key']}, function(error) {
    driver = createBrowserStackSession(config, caps);
  });

  ///// Your step definitions /////
  //
  // use 'Given', 'When' and 'Then' to declare step definitions
  //

  When(/^I open site$/, function (next) {
    driver.get('http://127.0.0.1/').then(next);
  });

  Then(/^I should see title "([^"]*)"$/, function (titleMatch, next) {
    driver.getTitle()
      .then(function(title) {
        assert.equal(title, titleMatch, next, 'Expected title to be ' + titleMatch);
      });
  });

  setTimeout(driver.quit, 5000);

});
<|endoftext|>


<commit_before>'use strict';

import * as angular from 'angular';
import _ from 'lodash';

import { AccountService, FirewallLabels } from '@spinnaker/core';
import { AMAZON_SECURITYGROUP_CONFIGURE_CONFIGSECURITYGROUP_MIXIN_CONTROLLER } from '../configure/configSecurityGroup.mixin.controller';

export const AMAZON_SECURITYGROUP_CLONE_CLONESECURITYGROUP_CONTROLLER =
  'spinnaker.amazon.securityGroup.clone.controller';
export const name = AMAZON_SECURITYGROUP_CLONE_CLONESECURITYGROUP_CONTROLLER; // for backwards compatibility
angular
  .module(AMAZON_SECURITYGROUP_CLONE_CLONESECURITYGROUP_CONTROLLER, [
    AMAZON_SECURITYGROUP_CONFIGURE_CONFIGSECURITYGROUP_MIXIN_CONTROLLER,
  ])
  .controller('awsCloneSecurityGroupController', [
    '$scope',
    '$uibModalInstance',
    '$controller',
    'securityGroup',
    'application',
    function($scope, $uibModalInstance, $controller, securityGroup, application) {
      const vm = this;

      vm.firewallLabel = FirewallLabels.get('Firewall');

      $scope.pages = {
        location: require('../configure/createSecurityGroupProperties.html'),
        ingress: require('../configure/createSecurityGroupIngress.html'),
      };

      securityGroup.credentials = securityGroup.accountName;
      $scope.namePreview = securityGroup.name;

      angular.extend(
        this,
        $controller('awsConfigSecurityGroupMixin', {
          $scope: $scope,
          $uibModalInstance: $uibModalInstance,
          application: application,
          securityGroup: securityGroup,
        }),
      );

      // We want to let people clone as a means to copy security groups across
      // regions so don't block them because the names already exist.
      $scope.allowDuplicateNames = true;

      AccountService.listAccounts('aws').then(function(accounts) {
        $scope.accounts = accounts;
        vm.accountUpdated();
      });

      securityGroup.securityGroupIngress = _.chain(securityGroup.inboundRules)
        .filter(function(rule) {
          return rule.securityGroup;
        })
        .map(function(rule) {
          return rule.portRanges.map(function(portRange) {
            return {
              name: rule.securityGroup.name,
              type: rule.protocol,
              startPort: portRange.startPort,
              endPort: portRange.endPort,
            };
          });
        })
        .flatten()
        .value();

      securityGroup.ipIngress = _.chain(securityGroup.inboundRules)
        .filter(function(rule) {
          return rule.range;
        })
        .map(function(rule) {
          return rule.portRanges.map(function(portRange) {
            return {
              cidr: rule.range.ip + rule.range.cidr,
              type: rule.protocol,
              startPort: portRange.startPort,
              endPort: portRange.endPort,
            };
          });
        })
        .flatten()
        .value();

      vm.upsert = function() {
        // <account-select-field> only updates securityGroup.credentials, but Orca looks at account* before looking at credentials
        // Updating the rest of the attributes to send the correct (expected) account for all attributes
        const { credentials } = $scope.securityGroup;
        Object.assign($scope.securityGroup, {
          account: credentials,
          accountName: credentials,
          accountId: credentials,
        });

        vm.mixinUpsert('Clone');
      };

      vm.initializeSecurityGroups();
    },
  ]);
<commit_msg>fix(aws): Fix to set right state while cloning security group<commit_after>'use strict';

import * as angular from 'angular';
import _ from 'lodash';

import { AccountService, FirewallLabels } from '@spinnaker/core';
import { AMAZON_SECURITYGROUP_CONFIGURE_CONFIGSECURITYGROUP_MIXIN_CONTROLLER } from '../configure/configSecurityGroup.mixin.controller';

export const AMAZON_SECURITYGROUP_CLONE_CLONESECURITYGROUP_CONTROLLER =
  'spinnaker.amazon.securityGroup.clone.controller';
export const name = AMAZON_SECURITYGROUP_CLONE_CLONESECURITYGROUP_CONTROLLER; // for backwards compatibility
angular
  .module(AMAZON_SECURITYGROUP_CLONE_CLONESECURITYGROUP_CONTROLLER, [
    AMAZON_SECURITYGROUP_CONFIGURE_CONFIGSECURITYGROUP_MIXIN_CONTROLLER,
  ])
  .controller('awsCloneSecurityGroupController', [
    '$scope',
    '$uibModalInstance',
    '$controller',
    'securityGroup',
    'application',
    function($scope, $uibModalInstance, $controller, securityGroup, application) {
      const vm = this;

      vm.firewallLabel = FirewallLabels.get('Firewall');

      $scope.pages = {
        location: require('../configure/createSecurityGroupProperties.html'),
        ingress: require('../configure/createSecurityGroupIngress.html'),
      };

      securityGroup.credentials = securityGroup.accountName;
      $scope.namePreview = securityGroup.name;

      angular.extend(
        this,
        $controller('awsConfigSecurityGroupMixin', {
          $scope: $scope,
          $uibModalInstance: $uibModalInstance,
          application: application,
          securityGroup: securityGroup,
        }),
      );
      $scope.state.isNew = true;
      // We want to let people clone as a means to copy security groups across
      // regions so don't block them because the names already exist.
      $scope.allowDuplicateNames = true;

      AccountService.listAccounts('aws').then(function(accounts) {
        $scope.accounts = accounts;
        vm.accountUpdated();
      });

      securityGroup.securityGroupIngress = _.chain(securityGroup.inboundRules)
        .filter(function(rule) {
          return rule.securityGroup;
        })
        .map(function(rule) {
          return rule.portRanges.map(function(portRange) {
            return {
              name: rule.securityGroup.name,
              type: rule.protocol,
              startPort: portRange.startPort,
              endPort: portRange.endPort,
            };
          });
        })
        .flatten()
        .value();

      securityGroup.ipIngress = _.chain(securityGroup.inboundRules)
        .filter(function(rule) {
          return rule.range;
        })
        .map(function(rule) {
          return rule.portRanges.map(function(portRange) {
            return {
              cidr: rule.range.ip + rule.range.cidr,
              type: rule.protocol,
              startPort: portRange.startPort,
              endPort: portRange.endPort,
            };
          });
        })
        .flatten()
        .value();

      vm.upsert = function() {
        // <account-select-field> only updates securityGroup.credentials, but Orca looks at account* before looking at credentials
        // Updating the rest of the attributes to send the correct (expected) account for all attributes
        const { credentials } = $scope.securityGroup;
        Object.assign($scope.securityGroup, {
          account: credentials,
          accountName: credentials,
          accountId: credentials,
        });

        vm.mixinUpsert('Clone');
      };

      vm.initializeSecurityGroups();
    },
  ]);
<|endoftext|>


<commit_before>define([], function() {
    var MoxieConf = {
        endpoint: 'http://api.m.ox.ac.uk',
        titlePrefix: 'Mobile Oxford - ',
        paths: {
            places_search: '/places/search',
            places_categories: '/places/types',
            places_id: '/places/',
            dates: '/dates/today',
            courses_search: '/courses/search',
            courses_subjects: '/courses/subjects',
            courses_bookings: '/courses/bookings',
            course_id: '/courses/course/',
            presentation_id: '/courses/presentation/',
            courses_auth_verify: '/courses/oauth/verify',
            courses_auth_authorized: '/courses/oauth/authorized',
            courses_auth_authorize: '/courses/oauth/authorize',
            library_search: '/library/search',
            library_item: '/library/item:',
            contact_search: '/contact/search'
        },
        urlFor: function(api_method) {
            return this.endpoint + this.paths[api_method];
        },
        pathFor: function(api_method) {
            return this.paths[api_method];
        },
        geolocationInterval: 25000,
        defaultLocation: {coords: {latitude: 51.752018, longitude: -1.257723}},
        mapbox: {key: 'mobileox.map-iihxb1dl'},
        map: {bounds: {exponent: 0.75, limit: 500, fallback: 5}},
        news: {
            feeds: [
                    {"title": "Department of Biochemistry", "url": "http://rss.oucs.ox.ac.uk/bioch/news/rss20.xml", "slug": "biochemistry-department"},
                    {"title": "Department of Computer Science", "url": "http://www.cs.ox.ac.uk/feeds/News-All.xml", "slug": "cs-news"},
                    {"title": "News from the RSL", "url": "http://rss.oucs.ox.ac.uk/oxitems/generatersstwo2.php?channel_name=ulib/science", "slug": "ulib-science"},
                    {"title": "Linacre College", "url": "http://www.linacre.ox.ac.uk/Linacre/news-and-events/news/RSS", "slug": "linacre"},
                    {"title": "Lady Margaret Hall news", "url": "http://www.lmh.ox.ac.uk/CMSPages/NewsRss.aspx", "slug": "lmh"},
                    {"title": "University of Oxford - Media", "url": "http://www.ox.ac.uk/news_rss.rm", "slug": "offices-media"},
                    {"title": "Student News Twitter Feed", "url": "http://twitter.com/statuses/user_timeline/uniofoxfordsi.rss", "slug": "student-news-twitter"},
                    {"title": "St. Antony's College Events", "url": "http://www.google.com/calendar/feeds/it-support%40sant.ox.ac.uk/public/basic?orderby=starttime&sortorder=ascending&futureevents=true&singleevents=true", "slug": "st-antonys-events"},
                    {"title": "Wolfson College", "url": "http://www.wolfson.ox.ac.uk/rss.xml", "slug": "wolfson"},
                    {"title": "Oriel College", "url": "http://www.oriel.ox.ac.uk/news/rss", "slug": "oriel-news"},
                    {"title": "Somerville College ROQ Blog", "url": "http://roq.some.ox.ac.uk/?feed=atom", "slug": "some-roq"},
                    {"title": "Oxford University Rowing Club Twitter Feed", "url": "http://twitter.com/statuses/user_timeline/5741492.rss", "slug": "rowing-club"},
                    {"title": "ClimatePrediction.net", "url": "http://climateprediction.net/rss.xml", "slug": "climate-predication"},
                ],
            numberOfEntries: 10,
        }
    };
    return MoxieConf;
});
<commit_msg>Re-ordering and added our team blog<commit_after>define([], function() {
    var MoxieConf = {
        endpoint: 'http://api.m.ox.ac.uk',
        titlePrefix: 'Mobile Oxford - ',
        paths: {
            places_search: '/places/search',
            places_categories: '/places/types',
            places_id: '/places/',
            dates: '/dates/today',
            courses_search: '/courses/search',
            courses_subjects: '/courses/subjects',
            courses_bookings: '/courses/bookings',
            course_id: '/courses/course/',
            presentation_id: '/courses/presentation/',
            courses_auth_verify: '/courses/oauth/verify',
            courses_auth_authorized: '/courses/oauth/authorized',
            courses_auth_authorize: '/courses/oauth/authorize',
            library_search: '/library/search',
            library_item: '/library/item:',
            contact_search: '/contact/search'
        },
        urlFor: function(api_method) {
            return this.endpoint + this.paths[api_method];
        },
        pathFor: function(api_method) {
            return this.paths[api_method];
        },
        geolocationInterval: 25000,
        defaultLocation: {coords: {latitude: 51.752018, longitude: -1.257723}},
        mapbox: {key: 'mobileox.map-iihxb1dl'},
        map: {bounds: {exponent: 0.75, limit: 500, fallback: 5}},
        news: {
            feeds: [
                    {"title": "University of Oxford - Media", "url": "http://www.ox.ac.uk/news_rss.rm", "slug": "offices-media"},
                    {"title": "Wolfson College", "url": "http://www.wolfson.ox.ac.uk/rss.xml", "slug": "wolfson"},
                    {"title": "Linacre College", "url": "http://www.linacre.ox.ac.uk/Linacre/news-and-events/news/RSS", "slug": "linacre"},
                    {"title": "Lady Margaret Hall news", "url": "http://www.lmh.ox.ac.uk/CMSPages/NewsRss.aspx", "slug": "lmh"},
                    {"title": "Oriel College", "url": "http://www.oriel.ox.ac.uk/news/rss", "slug": "oriel-news"},
                    {"title": "St. Antony's College Events", "url": "http://www.google.com/calendar/feeds/it-support%40sant.ox.ac.uk/public/basic?orderby=starttime&sortorder=ascending&futureevents=true&singleevents=true", "slug": "st-antonys-events"},
                    {"title": "Mobile Oxford Team Blog", "url": "http://blog.m.ox.ac.uk/feeds/all.atom.xml", "slug": "mox-blog"},
                    {"title": "Department of Biochemistry", "url": "http://rss.oucs.ox.ac.uk/bioch/news/rss20.xml", "slug": "biochemistry-department"},
                    {"title": "Department of Computer Science", "url": "http://www.cs.ox.ac.uk/feeds/News-All.xml", "slug": "cs-news"},
                    {"title": "News from the RSL", "url": "http://rss.oucs.ox.ac.uk/oxitems/generatersstwo2.php?channel_name=ulib/science", "slug": "ulib-science"},
                    {"title": "Student News Twitter Feed", "url": "http://twitter.com/statuses/user_timeline/uniofoxfordsi.rss", "slug": "student-news-twitter"},
                    {"title": "Somerville College ROQ Blog", "url": "http://roq.some.ox.ac.uk/?feed=atom", "slug": "some-roq"},
                    {"title": "Oxford University Rowing Club Twitter Feed", "url": "http://twitter.com/statuses/user_timeline/5741492.rss", "slug": "rowing-club"},
                    {"title": "ClimatePrediction.net", "url": "http://climateprediction.net/rss.xml", "slug": "climate-predication"},
                ],
            numberOfEntries: 10,
        }
    };
    return MoxieConf;
});
<|endoftext|>