<commit_before>/*
* mvc
* author: ronglin
* create date: 2014.6.24
*/

'use strict';

var parse = require('url').parse,
    utils = require('./utilities'),
    mvcView = require('./mvcView'),
    mvcAreas = require('./mvcAreas'),
    mvcHelper = require('./mvcHelper'),
    mvcMatcher = require('./mvcMatcher'),
    mvcController = require('./mvcController'),
    mvcMiddleware = require('./mvcMiddleware');

var mvcHandler = function(set) {

    var macher = mvcMatcher({
        sensitive: false,
        strict: false,
        end: false
    });

    var lower = function(str) {
        return mvcHelper.lower(str);
    };

    var getParam = function(routeData, findName, defaultIndex) {
        return mvcHelper.findRouteValue(routeData, findName, defaultIndex);
    };

    // route core
    return function(req, res, next) {
        //
        mvcMiddleware.xHeaders().handle(req, res);
        mvcMiddleware.ruleeUrl().handle(req, res);
        mvcMiddleware.ruleeForm().handle(req, res);
        mvcMiddleware.ruleeQuery().handle(req, res);
        mvcMiddleware.ruleeSecure().handle(req, res);
        //
        var matched = false, exception;
        var wrapNext = function() {
            if (exception) {
                if (!(exception instanceof Error)) {
                    exception = new Error(exception);
                }
                next(exception);
            }
            else if (!matched) {
                next();
            }
        };
        //
        var allAreas = mvcAreas.all();
        var pathName = parse(req.url).pathname;
        //
        utils.each(allAreas, function(i, area) {
            if (matched || exception) { return false; } // break
            //
            utils.each(area.routes, function(k, route) {
                var match = macher(route.expression);
                var routeData = match(pathName);
                if (routeData === false) { return; } // continue
                //
                var areaParam = getParam(routeData, 'area');
                if (!areaParam) {
                    routeData.unshift({
                        name: 'area',
                        value: area.name
                    });
                }
                //
                var controllerParam = getParam(routeData, 'controller', 1);
                if (!controllerParam) { return; } // continue
                if (!controllerParam.value) {
                    controllerParam.value = route.defaultValues[lower(controllerParam.name)];
                }
                //
                var controller = area.findController(controllerParam.value);
                if (!controller) { return; } // continue
                //
                var actionParam = getParam(routeData, 'action', 2);
                if (!actionParam) { return; } // continue
                if (!actionParam.value) {
                    actionParam.value = route.defaultValues[lower(actionParam.name)];
                }
                //
                try {
                    controller = controller.clone();
                    controller.initialize(req, res, route, mvcAreas.routeSet(), routeData);
                } catch (ex) {
                    controller.destroy();
                    exception = ex;
                    return false; // break
                }
                //
                var action = controller.findAction(actionParam.value, req.method, req.secure);
                if (!action) {
                    controller.destroy();
                    return; // continue
                }
                //
                try {
                    matched = true;
                    var executeResult = function(obj) {
                        if (obj !== undefined && obj !== null) {
                            executeResult = function(obj) { };
                            exception = action.executeResult(obj);
                            controller.destroy();
                            wrapNext();
                        }
                    };
                    executeResult(action.execute(function(result) {
                        executeResult(result);
                    }));
                } catch (ex) {
                    controller.destroy();
                    exception = ex;
                    return false; // break
                }
                //
                return false; // break
            });
        });
        // next
        wrapNext();
    };
};

var httpRawHandler = function(set) {
    var inner = mvcHandler(set), ct = { 'Content-Type': 'text/plain' };
    return function(req, res) {
        inner(req, res, function(err) {
            if (err) {
                res.writeHead(err.status || 500, ct);
                res.end(err.message);
            } else {
                res.writeHead(404, ct);
                res.end('Not Found');
            }
        });
    };
};

var expressHandler = function(set) {
    var inner = mvcHandler(set);
    return function(req, res, next) {
        inner(req, res, next);
    };
};

module.exports = {
    view: mvcView,
    areas: mvcAreas,
    controller: mvcController.define,
    //
    httpRawHandler: httpRawHandler,
    expressHandler: expressHandler
};
<commit_msg>fix bug on filling route default values<commit_after>/*
* mvc
* author: ronglin
* create date: 2014.6.24
*/

'use strict';

var parse = require('url').parse,
    utils = require('./utilities'),
    mvcView = require('./mvcView'),
    mvcAreas = require('./mvcAreas'),
    mvcHelper = require('./mvcHelper'),
    mvcMatcher = require('./mvcMatcher'),
    mvcController = require('./mvcController'),
    mvcMiddleware = require('./mvcMiddleware');

var mvcHandler = function(set) {

    var macher = mvcMatcher({
        sensitive: false,
        strict: false,
        end: false
    });

    var getParam = function(routeData, findName, defaultIndex) {
        return mvcHelper.findRouteValue(routeData, findName, defaultIndex);
    };

    // route core
    return function(req, res, next) {
        //
        mvcMiddleware.xHeaders().handle(req, res);
        mvcMiddleware.ruleeUrl().handle(req, res);
        mvcMiddleware.ruleeForm().handle(req, res);
        mvcMiddleware.ruleeQuery().handle(req, res);
        mvcMiddleware.ruleeSecure().handle(req, res);
        //
        var matched = false, exception;
        var wrapNext = function() {
            if (exception) {
                if (!(exception instanceof Error)) {
                    exception = new Error(exception);
                }
                next(exception);
            }
            else if (!matched) {
                next();
            }
        };
        //
        var allAreas = mvcAreas.all();
        var pathName = parse(req.url).pathname;
        //
        utils.each(allAreas, function(i, area) {
            if (matched || exception) { return false; } // break
            //
            utils.each(area.routes, function(k, route) {
                var match = macher(route.expression);
                var routeData = match(pathName);
                if (routeData === false) { return; } // continue
                //
                utils.each(routeData, function() {
                    if (!this.value) {
                        var lowerName = this.name.toLowerCase();
                        if (lowerName in route.defaultValues) {
                            this.value = route.defaultValues[lowerName];
                        }
                    }
                });
                //
                var areaParam = getParam(routeData, 'area');
                if (!areaParam) {
                    routeData.unshift({
                        name: 'area',
                        value: area.name
                    });
                }
                //
                var controllerParam = getParam(routeData, 'controller', 1);
                if (!controllerParam) { return; } // continue
                //
                var controller = area.findController(controllerParam.value);
                if (!controller) { return; } // continue
                //
                var actionParam = getParam(routeData, 'action', 2);
                if (!actionParam) { return; } // continue
                //
                try {
                    controller = controller.clone();
                    controller.initialize(req, res, route, mvcAreas.routeSet(), routeData);
                } catch (ex) {
                    controller.destroy();
                    exception = ex;
                    return false; // break
                }
                //
                var action = controller.findAction(actionParam.value, req.method, req.secure);
                if (!action) {
                    controller.destroy();
                    return; // continue
                }
                //
                try {
                    matched = true;
                    var executeResult = function(obj) {
                        if (obj !== undefined && obj !== null) {
                            executeResult = function(obj) { };
                            exception = action.executeResult(obj);
                            controller.destroy();
                            wrapNext();
                        }
                    };
                    executeResult(action.execute(function(result) {
                        executeResult(result);
                    }));
                } catch (ex) {
                    controller.destroy();
                    exception = ex;
                    return false; // break
                }
                //
                return false; // break
            });
        });
        // next
        wrapNext();
    };
};

var httpRawHandler = function(set) {
    var inner = mvcHandler(set), ct = { 'Content-Type': 'text/plain' };
    return function(req, res) {
        inner(req, res, function(err) {
            if (err) {
                res.writeHead(err.status || 500, ct);
                res.end(err.message);
            } else {
                res.writeHead(404, ct);
                res.end('Not Found');
            }
        });
    };
};

var expressHandler = function(set) {
    var inner = mvcHandler(set);
    return function(req, res, next) {
        inner(req, res, next);
    };
};

module.exports = {
    view: mvcView,
    areas: mvcAreas,
    controller: mvcController.define,
    //
    httpRawHandler: httpRawHandler,
    expressHandler: expressHandler
};
<|endoftext|>


<commit_before>+ function($) {
    'use strict';

    // UPLOAD CLASS DEFINITION
    // ======================

    var dropZone = document.getElementById('drop-zone');
    var uploadForm = document.getElementById('js-upload-form');

    var startUpload = function(files) {
        console.log(files)
    }

    uploadForm.addEventListener('submit', function(e) {
        var uploadFiles = document.getElementById('js-upload-files').files;
        e.preventDefault()

        startUpload(uploadFiles)
    })

    dropZone.ondrop = function(e) {
        e.preventDefault();
        this.className = 'upload-drop-zone';

        startUpload(e.dataTransfer.files)
    }

    dropZone.ondragover = function() {
        this.className = 'upload-drop-zone drop';
        return false;
    }

    dropZone.ondragleave = function() {
        this.className = 'upload-drop-zone';
        return false;
    }

}(jQuery);<commit_msg>Remove unused `dragdrop.js`<commit_after><|endoftext|>


<commit_before>import _ from 'lodash'

import { isThenable, syncOrThen } from './util/promiseUtil'
import Collection from './Collection'
import { calcFindKey, normalizeQuery } from './util/queryUtil'

export default class FetchingCollection extends Collection {
  // NOTE expecting overriding
  // onFetch() {}
  // calcFetchKey() {}
  isAsyncFetch = false

  _fetchTimes = {}
  _fetchPromises = {}

  calcFetchKey(query, option) {
    return calcFindKey(query, option)
  }

  _getQueryIds(query) {
    if (!query) return null
    const matcher = query[this.idField]
    if (!matcher) return null
    return Array.isArray(matcher.$in) ? matcher.$in : [matcher]
  }

  find(query, option = {}) {
    if (this.onFetch) {
      const fetchQuery = normalizeQuery(query, this.idField, this.isLocalId)
      if (fetchQuery) {
        // NOTE diff behavior for Sync and Async
        const cacheKey = this.calcFetchKey(fetchQuery, option)
        if (this._shouldReload(cacheKey, option.load)) {
          const result = this._doReload(fetchQuery, option, cacheKey)

          const { duringMapState } = this._store.getContext()
          if (!duringMapState && (option.load === 'reload' || option.load === 'load')) {
            // TODO compare local and remote result, drop if backend is removed
            return syncOrThen(result, () => super.find(query, option))
          }
        }
      }
    }
    return super.find(query, option)
  }

  get(id, option = {}) {
    if (this.onFetch) {
      // NOTE diff behavior for Sync and Async
      if (this.isAsyncFetch) {
        if (id && !this.isLocalId(id) && this._shouldReload(id, option.load)) {
          // Async (batch ids in here)
          this._fetchIdTable[id] = 1
          this._fetchByIdsDebounce()
        }
      } else {
        this._doReload([id])
      }
    }
    return super.get(id, option)
  }
  _fetchIdTable = []
  _fetchByIdsPromise = null
  _fetchByIdsDebounce() {
    if (this._fetchByIdsPromise) return this._fetchByIdsPromise

    const promises = _.values(this._fetchPromises)
    this._fetchByIdsPromise = Promise.all(promises)
      .then(() => {
        const ids = Object.keys(this._fetchIdTable)
        if (ids.length > 0) {
          return this._doReload(ids)
        }
      })
      .then(() => (this._fetchByIdsPromise = null))
      .catch(() => (this._fetchByIdsPromise = null))
  }

  _shouldReload(cacheKey, mode) {
    if (mode === 'local') return false
    const fetchTime = this._fetchTimes[cacheKey]

    // console.log('this._store.getContext().duringServerPreload', this._store.getContext().duringServerPreload, mode === 'preload' && !fetchTime)
    if (this._store.getContext().duringServerPreload) {
      // duringServerPreload, only load resource that is mark as preload and preload only one time
      return mode === 'preload' && !fetchTime
    }

    // TODO CronJob to clear _fetchTimes & cached values
    return mode === 'reload' || !fetchTime
  }

  _doReload(query, option, cacheKey) {
    let findingKey = cacheKey
    if (this.isAsyncFetch) {
      // is loading (promise exists but not deleted)
      if (findingKey === undefined) findingKey = this.calcFetchKey(query, option)
      const oldPromise = this._fetchPromises[findingKey]
      if (oldPromise) {
        console.warn('try to fetch same ajax query while old ajax call is running')
        return oldPromise
      }
    }

    // NOTE should be able to handle Both Async and Sync onFetch
    const result = this.onFetch(query, option)

    const fetchIsAsync = (this.isAsyncFetch = isThenable(result))
    if (fetchIsAsync) {
      // uniq promise
      if (findingKey === undefined) findingKey = this.calcFetchKey(query, option)
      const now = new Date()
      // means start to fetch
      this._fetchTimes[findingKey] = now
      // prevent fetch by ids again for some ids
      _.each(this._getQueryIds(query), id => (this._fetchTimes[id] = now))

      // may not need promise anymore
      const promiseTable = this._fetchPromises
      promiseTable[findingKey] = result
      result
        .then(ret => {
          delete promiseTable[findingKey]

          if (_.isEmpty(ret)) {
            // force state change to ensure component known loading is done, but just load nothing
            this._store.dispatchNow()
          } else {
            const changes = this.importAll(ret)
            // skip setAll overriding
            this._setAll(changes)
            // store fetchTimes
            if (changes) {
              _.keys(changes).forEach(id => {
                this._fetchTimes[id] = now
              })
            }
          }

          // TODO compare local and remote result, drop if backend is removed
          // should return the processed ret array instead?
          return ret
        })
        .catch(err => {
          delete promiseTable[findingKey]
          if (__DEV__) console.error(err)
          return Promise.reject(err)
        })
    } else {
      // Async fetch result
      // skip setAll
      this._setAll(this.importAll(result))
    }

    return result
  }

  importAll(values) {
    const changes = _.reduce(
      values,
      (accumulator, value, key) => {
        if (value && this.isTidy(key)) {
          const doc = this.cast(value)
          const id = doc[this.idField] || key
          accumulator[id] = doc
        }
        return accumulator
      },
      {}
    )
    // GC here
    return changes
  }

  isTidy() {
    return true
  }

  getPromise() {
    const promises = _.values(this._fetchPromises)
    if (this._fetchByIdsPromise) promises.push(this._fetchByIdsPromise)
    const superPromise = super.getPromise && super.getPromise()
    if (superPromise) promises.push(superPromise)
    // console.log('getPromise()', _.values(this._fetchPromises), this._fetchByIdsPromise, superPromise)
    return promises.length > 0 ? Promise.all(promises) : null
  }

  isFetching() {
    return !!this._fetchByIdsPromise || Object.keys(this._fetchPromises).length > 0
  }

  invalidate() {
    if (super.invalidate) super.invalidate()
    this._fetchTimes = {}
    // NOTE Fetcher should combine with Stage, so no local changes will go to Fetcher wrapping collection
  }
}
<commit_msg>add reload, load function<commit_after>import _ from 'lodash'

import { isThenable, syncOrThen } from './util/promiseUtil'
import Collection from './Collection'
import { calcFindKey, normalizeQuery } from './util/queryUtil'

export default class FetchingCollection extends Collection {
  // NOTE expecting overriding
  // onFetch() {}
  // calcFetchKey() {}
  isAsyncFetch = false

  // TODO may need to pass _fetchTimes data from server to client
  _fetchTimes = {}
  _fetchPromises = {}

  calcFetchKey(query, option) {
    return calcFindKey(query, option)
  }

  _getQueryIds(query) {
    if (!query) return null
    const matcher = query[this.idField]
    if (!matcher) return null
    return Array.isArray(matcher.$in) ? matcher.$in : [matcher]
  }

  find(query, option = {}) {
    if (this.onFetch) {
      const fetchQuery = normalizeQuery(query, this.idField, this.isLocalId)
      if (fetchQuery) {
        // NOTE diff behavior for Sync and Async
        const cacheKey = this.calcFetchKey(fetchQuery, option)
        if (this._shouldReload(cacheKey, option.load)) {
          const result = this._doReload(fetchQuery, option, cacheKey)

          const { duringMapState } = this._store.getContext()
          if (!duringMapState && (option.load === 'reload' || option.load === 'load')) {
            // TODO compare local and remote result, drop if backend is removed
            return syncOrThen(result, () => super.find(query, option))
          }
        }
      }
    }
    return super.find(query, option)
  }

  get(id, option = {}) {
    if (this.onFetch) {
      // NOTE diff behavior for Sync and Async
      if (this.isAsyncFetch) {
        if (id && !this.isLocalId(id) && this._shouldReload(id, option.load)) {
          // Async (batch ids in here)
          this._fetchIdTable[id] = 1
          this._fetchByIdsDebounce()
        }
      } else {
        this._doReload([id])
      }
    }
    return super.get(id, option)
  }
  _fetchIdTable = []
  _fetchByIdsPromise = null
  _fetchByIdsDebounce() {
    if (this._fetchByIdsPromise) return this._fetchByIdsPromise

    const promises = _.values(this._fetchPromises)
    this._fetchByIdsPromise = Promise.all(promises)
      .then(() => {
        const ids = Object.keys(this._fetchIdTable)
        if (ids.length > 0) {
          return this._doReload(ids)
        }
      })
      .then(() => (this._fetchByIdsPromise = null))
      .catch(() => (this._fetchByIdsPromise = null))
  }

  _shouldReload(cacheKey, mode) {
    if (mode === 'local') return false
    const fetchTime = this._fetchTimes[cacheKey]

    // console.log('this._store.getContext().duringServerPreload', this._store.getContext().duringServerPreload, mode === 'preload' && !fetchTime)
    if (this._store.getContext().duringServerPreload) {
      // duringServerPreload, only load resource that is mark as preload and preload only one time
      return mode === 'preload' && !fetchTime
    }

    // TODO CronJob to clear _fetchTimes & cached values
    return mode === 'reload' || !fetchTime
  }

  _doReload(query, option, cacheKey) {
    let findingKey = cacheKey
    if (this.isAsyncFetch) {
      // is loading (promise exists but not deleted)
      if (findingKey === undefined) findingKey = this.calcFetchKey(query, option)
      const oldPromise = this._fetchPromises[findingKey]
      if (oldPromise) {
        console.warn('try to fetch same ajax query while old ajax call is running')
        return oldPromise
      }
    }

    // NOTE should be able to handle Both Async and Sync onFetch
    const result = this.onFetch(query, option)

    const fetchIsAsync = (this.isAsyncFetch = isThenable(result))
    if (fetchIsAsync) {
      // uniq promise
      if (findingKey === undefined) findingKey = this.calcFetchKey(query, option)
      const now = new Date()
      // means start to fetch
      this._fetchTimes[findingKey] = now
      // prevent fetch by ids again for some ids
      _.each(this._getQueryIds(query), id => (this._fetchTimes[id] = now))

      // may not need promise anymore
      const promiseTable = this._fetchPromises
      promiseTable[findingKey] = result
      result
        .then(ret => {
          delete promiseTable[findingKey]

          if (_.isEmpty(ret)) {
            // force state change to ensure component known loading is done, but just load nothing
            this._store.dispatchNow()
          } else {
            const changes = this.importAll(ret)
            // skip setAll overriding
            this._setAll(changes)
            // store fetchTimes
            if (changes) {
              _.keys(changes).forEach(id => {
                this._fetchTimes[id] = now
              })
            }
          }

          // TODO compare local and remote result, drop if backend is removed
          // should return the processed ret array instead?
          return ret
        })
        .catch(err => {
          delete promiseTable[findingKey]
          if (__DEV__) console.error(err)
          return Promise.reject(err)
        })
    } else {
      // Async fetch result
      // skip setAll
      this._setAll(this.importAll(result))
    }

    return result
  }

  importAll(values) {
    const changes = _.reduce(
      values,
      (accumulator, value, key) => {
        if (value && this.isTidy(key)) {
          const doc = this.cast(value)
          const id = doc[this.idField] || key
          accumulator[id] = doc
        }
        return accumulator
      },
      {}
    )
    // GC here
    // TODO compare local and remote result, drop if backend is removed
    return changes
  }

  isTidy() {
    return true
  }

  reload(query, option) {
    const fetchQuery = normalizeQuery(query, this.idField, this.isLocalId)
    const result = this._doReload(fetchQuery, option)
    return syncOrThen(result, () => super.find(query, option))
  }

  load(query, option = {}) {
    const fetchQuery = normalizeQuery(query, this.idField, this.isLocalId)
    // NOTE diff behavior for Sync and Async
    const cacheKey = this.calcFetchKey(fetchQuery, option)
    if (this._fetchTimes[cacheKey]) {
      const result = this._doReload(fetchQuery, option, cacheKey)
      return syncOrThen(result, () => super.find(query, option))
    }
    return super.find(query, option)
  }

  getPromise() {
    const promises = _.values(this._fetchPromises)
    if (this._fetchByIdsPromise) promises.push(this._fetchByIdsPromise)
    const superPromise = super.getPromise && super.getPromise()
    if (superPromise) promises.push(superPromise)
    // console.log('getPromise()', _.values(this._fetchPromises), this._fetchByIdsPromise, superPromise)
    return promises.length > 0 ? Promise.all(promises) : null
  }

  isFetching() {
    return !!this._fetchByIdsPromise || Object.keys(this._fetchPromises).length > 0
  }

  invalidate() {
    if (super.invalidate) super.invalidate()
    this._fetchTimes = {}
    // NOTE Fetcher should combine with Stage, so no local changes will go to Fetcher wrapping collection
  }
}
<|endoftext|>


<commit_before>/*global MAPJS, Color, _, jQuery, Kinetic*/
/*jslint nomen: true, newcap: true, browser: true*/
(function () {
	'use strict';
	/*shamelessly copied from http://james.padolsey.com/javascript/wordwrap-for-javascript */
	var COLUMN_WORD_WRAP_LIMIT = 25;
	function wordWrap(str, width, brk, cut) {
		brk = brk || '\n';
		width = width || 75;
		cut = cut || false;
		if (!str) {
			return str;
		}
		var regex = '.{1,' + width + '}(\\s|$)' + (cut ? '|.{' + width + '}|.+$' : '|\\S+?(\\s|$)');
		return str.match(new RegExp(regex, 'g')).join(brk);
	}
	function joinLines(string) {
		return string.replace(/\n/g, ' ');
	}
	function breakWords(string) {
		return wordWrap(joinLines(string), COLUMN_WORD_WRAP_LIMIT, '\n', false);
	}
	function createLink() {
		var link = new Kinetic.Group(),
			rectProps = {
				width: 10,
				height: 20,
				rotation: 0.6,
				stroke: '#555555',
				strokeWidth: 3,
				cornerRadius: 6,
				shadowOffset: [2, 2],
				shadow: '#CCCCCC',
				shadowBlur: 0.4,
				shadowOpacity: 0.4,
			},
			rect = new Kinetic.Rect(rectProps),
			rect2 = new Kinetic.Rect(rectProps);
		rect2.attrs.x = 7;
		rect2.attrs.y = -7;
		link.add(rect);
		link.add(rect2);
		link.setActive = function (isActive) {
			rect.attrs.stroke = rect2.attrs.stroke = (isActive ? 'black' : '#555555');
			link.getLayer().draw();
		};
		return link;
	}
	function createClip() {
		var group, clip, props = {width: 5, height: 25, radius: 3, rotation: 0.1, strokeWidth: 2, clipTo: 10};
		group = new Kinetic.Group();
		group.getClipMargin = function () {
			return props.clipTo;
		};
		group.add(new Kinetic.Clip(_.extend({stroke: 'darkslategrey', x: 1, y: 1}, props)));
		clip = new Kinetic.Clip(_.extend({stroke: 'skyblue'}, props));
		group.add(clip);
		group.on('mouseover', function () {
			clip.attrs.stroke = 'black';
			group.getLayer().draw();
		});
		group.on('mouseout', function () {
			clip.attrs.stroke = 'skyblue';
			group.getLayer().draw();
		});

		return group;
	}
	Kinetic.Idea = function (config) {
		var ENTER_KEY_CODE = 13,
			ESC_KEY_CODE = 27,
			self = this,
			unformattedText = joinLines(config.text),
			bgRect = function (offset) {
				return new Kinetic.Rect({
					strokeWidth: 1,
					cornerRadius: 10,
					x: offset,
					y: offset,
					visible: false
				});
			};
		this.level = config.level;
		this.mmAttr = config.mmAttr;
		this.isSelected = false;
		config.draggable = config.level > 1;
		config.name = 'Idea';
		Kinetic.Group.call(this, config);
		this.rect = new Kinetic.Rect({
			strokeWidth: 1,
			cornerRadius: 10
		});
		this.rectbg1 = bgRect(8);
		this.rectbg2 = bgRect(4);
		this.link = createLink();
		this.link.on('click tap', function () {
			var url = MAPJS.URLHelper.getLink(unformattedText);
			if (url) {
				window.open(url, '_blank');
			}
		});
		this.link.on('mouseover', function () {
			self.link.setActive(true);
		});
		this.link.on('mouseout', function () {
			self.link.setActive(false);
		});
		this.text = new Kinetic.Text({
			fontSize: 12,
			fontFamily: 'Helvetica',
			lineHeight: 1.5,
			fontStyle: 'bold',
			align: 'center'
		});
		this.clip = createClip();
		this.clip.on('click tap', function () {
			self.fire(':request', {type: 'openAttachment', source: 'mouse'});
		});
		this.add(this.rectbg1);
		this.add(this.rectbg2);
		this.add(this.rect);
		this.add(this.text);
		this.add(this.link);
		this.add(this.clip);
		this.activeWidgets = [this.link, this.clip];
		this.setText = function (text) {
			var replacement = breakWords(MAPJS.URLHelper.stripLink(text)) ||
					(text.length < COLUMN_WORD_WRAP_LIMIT ? text : (text.substring(0, COLUMN_WORD_WRAP_LIMIT) + '...'));
			unformattedText = text;
			self.text.setText(replacement);
			self.link.setVisible(MAPJS.URLHelper.containsLink(text));
			self.setStyle();
		};
		this.setText(config.text);
		this.classType = 'Idea';
		this.getNodeAttrs = function () {
			return self.attrs;
		};
		this.isVisible = function (offset) {
			var stage = self.getStage();
			return stage && stage.isRectVisible(new MAPJS.Rectangle(self.attrs.x, self.attrs.y, self.getWidth(), self.getHeight()), offset);
		};
		this.editNode = function (shouldSelectAll, deleteOnCancel) {
			self.fire(':editing');
			self.getLayer().draw();
			var canvasPosition = jQuery(self.getLayer().getCanvas().getElement()).offset(),
				ideaInput,
				onStageMoved = _.throttle(function () {
					ideaInput.css({
						top: canvasPosition.top + self.getAbsolutePosition().y,
						left: canvasPosition.left + self.getAbsolutePosition().x
					});
				}, 10),
				updateText = function (newText) {
					self.setStyle();
					self.getStage().draw();
					self.fire(':textChanged', {
						text: newText || unformattedText
					});
					ideaInput.remove();
					self.stopEditing = undefined;
					self.getStage().off('xChange yChange', onStageMoved);
				},
				onCommit = function () {
					updateText(ideaInput.val());
				},
				onCancelEdit = function () {
					updateText(unformattedText);
					if (deleteOnCancel) {
						self.fire(':request', {type: 'removeSubIdea', source: 'internal'});
					}
				},
				scale = self.getStage().getScale().x || 1;
			ideaInput = jQuery('<textarea type="text" wrap="soft" class="ideaInput"></textarea>')
				.css({
					top: canvasPosition.top + self.getAbsolutePosition().y,
					left: canvasPosition.left + self.getAbsolutePosition().x,
					width: (6 + self.getWidth()) * scale,
					height: (6 + self.getHeight()) * scale,
					'padding': 3 * scale + 'px',
					'font-size': self.text.attrs.fontSize * scale + 'px',
					'line-height': '150%',
					'background-color': self.getBackground(),
					'margin': -3 * scale,
					'border-radius': self.rect.attrs.cornerRadius * scale + 'px',
					'border': self.rect.attrs.strokeWidth * (2 * scale) + 'px dashed ' + self.rect.attrs.stroke,
					'color': self.text.attrs.fill
				})
				.val(unformattedText)
				.appendTo('body')
				.keydown(function (e) {
					if (e.which === ENTER_KEY_CODE) {
						onCommit();
					} else if (e.which === ESC_KEY_CODE) {
						onCancelEdit();
					} else if (e.which === 9) {
						onCommit();
						e.preventDefault();
						self.fire(':request', {type: 'addSubIdea', source: 'keyboard'});
						return;
					} else if (e.which === 83 && (e.metaKey || e.ctrlKey)) {
						e.preventDefault();
						onCommit();
						return; /* propagate to let the environment handle ctrl+s */
					} else if (!e.shiftKey && e.which === 90 && (e.metaKey || e.ctrlKey)) {
						if (ideaInput.val() === unformattedText) {
							onCancelEdit();
						}
					}
					e.stopPropagation();
				})
				.blur(onCommit)
				.focus(function () {
					if (shouldSelectAll) {
						if (ideaInput[0].setSelectionRange) {
							ideaInput[0].setSelectionRange(0, unformattedText.length);
						} else {
							ideaInput.select();
						}
					} else if (ideaInput[0].setSelectionRange) {
						ideaInput[0].setSelectionRange(unformattedText.length, unformattedText.length);
					}
				})
				.on('input', function () {
					var text = new Kinetic.Idea({
						text: ideaInput.val()
					});
					ideaInput.width(Math.max(ideaInput.width(), text.getWidth() * scale));
					ideaInput.height(Math.max(ideaInput.height(), text.getHeight() * scale));
				});

			self.stopEditing = onCancelEdit;
			ideaInput.focus();

			self.getStage().on('xChange yChange', onStageMoved);
		};
	};
}());

Kinetic.Idea.prototype.setShadowOffset = function (offset) {
	'use strict';
	offset = this.getMMScale().x * offset;
	_.each([this.rect, this.rectbg1, this.rectbg2], function (r) {
		r.setShadowOffset([offset, offset]);
	});
};

Kinetic.Idea.prototype.getMMScale = function () {
	'use strict';
	var stage = this.getStage(),
		scale = (stage && stage.attrs && stage.attrs.scale && stage.attrs.scale.x) || (this.attrs && this.attrs.scale && this.attrs.scale.x) || 1;
	return {x: scale, y: scale};
};

Kinetic.Idea.prototype.setupShadows = function () {
	'use strict';
	var scale = this.getMMScale().x,
		isSelected = this.isSelected,
		offset = this.isCollapsed() ? 3 * scale : 4 * scale,
		normalShadow = {
			color: 'black',
			blur: 10 * scale,
			offset: [offset, offset],
			opacity: 0.4 * scale
		},
		selectedShadow = {
			color: 'black',
			blur: 0,
			offset: [offset, offset],
			opacity: 1
		},
		shadow = isSelected ? selectedShadow : normalShadow;
	_.each([this.rect, this.rectbg1, this.rectbg2], function (r) {
		r.setShadowColor(shadow.color);
		r.setShadowBlur(shadow.blur);
		r.setShadowOpacity(shadow.opacity);
		r.setShadowOffset(shadow.offset);
	});
};
Kinetic.Idea.prototype.getBackground = function () {
	'use strict';
	/*jslint newcap: true*/
	var isRoot = this.level === 1,
		defaultBg = MAPJS.defaultStyles[isRoot ? 'root' : 'nonRoot'].background,
		validColor = function (color, defaultColor) {
			if (!color) {
				return defaultColor;
			}
			var parsed = Color(color).hexString();
			return color.toUpperCase() === parsed.toUpperCase() ? color : defaultColor;
		};
	return validColor(this.mmAttr && this.mmAttr.style && this.mmAttr.style.background, defaultBg);
};
Kinetic.Idea.prototype.setStyle = function () {
	'use strict';
	/*jslint newcap: true*/
	var self = this,
		isDroppable = this.isDroppable,
		isSelected = this.isSelected,
		background = this.getBackground(),
		tintedBackground = Color(background).mix(Color('#EEEEEE')).hexString(),
		isClipVisible = this.mmAttr && this.mmAttr.attachment || false,
		padding = 8,
		clipMargin = isClipVisible ? this.clip.getClipMargin() : 0,
		rectOffset = clipMargin,
		rectIncrement = 4;
	this.clip.setVisible(isClipVisible);
	this.attrs.width = this.text.getWidth() + 2 * padding;
	this.attrs.height = this.text.getHeight() + 2 * padding + clipMargin;
	this.text.attrs.x = padding;
	this.text.attrs.y = padding + clipMargin;
	this.link.attrs.x = this.text.getWidth() + 10;
	this.link.attrs.y = this.text.getHeight() + 5 + clipMargin;
	_.each([this.rect, this.rectbg2, this.rectbg1], function (r) {
		r.attrs.width = self.text.getWidth() + 2 * padding;
		r.attrs.height = self.text.getHeight() + 2 * padding;
		r.attrs.y = rectOffset;
		rectOffset += rectIncrement;
		if (isDroppable) {
			r.attrs.stroke = '#9F4F4F';
			r.attrs.fillLinearGradientStartPoint = {x: 0, y: 0};
			r.attrs.fillLinearGradientEndPoint = {x: 100, y: 100};
			background = '#EF6F6F';
			r.attrs.fillLinearGradientColorStops = [0, background, 1, '#CF4F4F'];
		} else if (isSelected) {
			r.attrs.fillLinearGradientColorStops = [0, background, 1, background];
		} else {
			r.attrs.stroke = '#888';
			r.attrs.fillLinearGradientStartPoint = {x: 0, y: 0};
			r.attrs.fillLinearGradientEndPoint = {x: 100, y: 100};
			r.attrs.fillLinearGradientColorStops = [0, tintedBackground, 1, background];
		}
	});
	this.rectbg1.setVisible(this.isCollapsed());
	this.rectbg2.setVisible(this.isCollapsed());
	this.clip.attrs.x = this.text.getWidth() + padding;
	this.setupShadows();
	this.text.attrs.fill = MAPJS.contrastForeground(tintedBackground);
};
Kinetic.Idea.prototype.setMMAttr = function (newMMAttr) {
	'use strict';
	this.mmAttr = newMMAttr;
	this.setStyle();
	this.getLayer().draw();
};
Kinetic.Idea.prototype.getIsSelected = function () {
	'use strict';
	return this.isSelected;
};
Kinetic.Idea.prototype.isCollapsed = function () {
	'use strict';
	return this.mmAttr && this.mmAttr.collapsed || false;
};

Kinetic.Idea.prototype.setIsSelected = function (isSelected) {
	'use strict';
	this.isSelected = isSelected;
	this.setStyle();
	this.getLayer().draw();
	if (!isSelected && this.stopEditing) {
		this.stopEditing();
	}
};
Kinetic.Idea.prototype.setIsDroppable = function (isDroppable) {
	'use strict';
	this.isDroppable = isDroppable;
	this.setStyle(this.attrs);
};
Kinetic.Global.extend(Kinetic.Idea, Kinetic.Group);
<commit_msg>undo instead of remove subidea - fixes insertIntermediate+esc<commit_after>/*global MAPJS, Color, _, jQuery, Kinetic*/
/*jslint nomen: true, newcap: true, browser: true*/
(function () {
	'use strict';
	/*shamelessly copied from http://james.padolsey.com/javascript/wordwrap-for-javascript */
	var COLUMN_WORD_WRAP_LIMIT = 25;
	function wordWrap(str, width, brk, cut) {
		brk = brk || '\n';
		width = width || 75;
		cut = cut || false;
		if (!str) {
			return str;
		}
		var regex = '.{1,' + width + '}(\\s|$)' + (cut ? '|.{' + width + '}|.+$' : '|\\S+?(\\s|$)');
		return str.match(new RegExp(regex, 'g')).join(brk);
	}
	function joinLines(string) {
		return string.replace(/\n/g, ' ');
	}
	function breakWords(string) {
		return wordWrap(joinLines(string), COLUMN_WORD_WRAP_LIMIT, '\n', false);
	}
	function createLink() {
		var link = new Kinetic.Group(),
			rectProps = {
				width: 10,
				height: 20,
				rotation: 0.6,
				stroke: '#555555',
				strokeWidth: 3,
				cornerRadius: 6,
				shadowOffset: [2, 2],
				shadow: '#CCCCCC',
				shadowBlur: 0.4,
				shadowOpacity: 0.4,
			},
			rect = new Kinetic.Rect(rectProps),
			rect2 = new Kinetic.Rect(rectProps);
		rect2.attrs.x = 7;
		rect2.attrs.y = -7;
		link.add(rect);
		link.add(rect2);
		link.setActive = function (isActive) {
			rect.attrs.stroke = rect2.attrs.stroke = (isActive ? 'black' : '#555555');
			link.getLayer().draw();
		};
		return link;
	}
	function createClip() {
		var group, clip, props = {width: 5, height: 25, radius: 3, rotation: 0.1, strokeWidth: 2, clipTo: 10};
		group = new Kinetic.Group();
		group.getClipMargin = function () {
			return props.clipTo;
		};
		group.add(new Kinetic.Clip(_.extend({stroke: 'darkslategrey', x: 1, y: 1}, props)));
		clip = new Kinetic.Clip(_.extend({stroke: 'skyblue'}, props));
		group.add(clip);
		group.on('mouseover', function () {
			clip.attrs.stroke = 'black';
			group.getLayer().draw();
		});
		group.on('mouseout', function () {
			clip.attrs.stroke = 'skyblue';
			group.getLayer().draw();
		});

		return group;
	}
	Kinetic.Idea = function (config) {
		var ENTER_KEY_CODE = 13,
			ESC_KEY_CODE = 27,
			self = this,
			unformattedText = joinLines(config.text),
			bgRect = function (offset) {
				return new Kinetic.Rect({
					strokeWidth: 1,
					cornerRadius: 10,
					x: offset,
					y: offset,
					visible: false
				});
			};
		this.level = config.level;
		this.mmAttr = config.mmAttr;
		this.isSelected = false;
		config.draggable = config.level > 1;
		config.name = 'Idea';
		Kinetic.Group.call(this, config);
		this.rect = new Kinetic.Rect({
			strokeWidth: 1,
			cornerRadius: 10
		});
		this.rectbg1 = bgRect(8);
		this.rectbg2 = bgRect(4);
		this.link = createLink();
		this.link.on('click tap', function () {
			var url = MAPJS.URLHelper.getLink(unformattedText);
			if (url) {
				window.open(url, '_blank');
			}
		});
		this.link.on('mouseover', function () {
			self.link.setActive(true);
		});
		this.link.on('mouseout', function () {
			self.link.setActive(false);
		});
		this.text = new Kinetic.Text({
			fontSize: 12,
			fontFamily: 'Helvetica',
			lineHeight: 1.5,
			fontStyle: 'bold',
			align: 'center'
		});
		this.clip = createClip();
		this.clip.on('click tap', function () {
			self.fire(':request', {type: 'openAttachment', source: 'mouse'});
		});
		this.add(this.rectbg1);
		this.add(this.rectbg2);
		this.add(this.rect);
		this.add(this.text);
		this.add(this.link);
		this.add(this.clip);
		this.activeWidgets = [this.link, this.clip];
		this.setText = function (text) {
			var replacement = breakWords(MAPJS.URLHelper.stripLink(text)) ||
					(text.length < COLUMN_WORD_WRAP_LIMIT ? text : (text.substring(0, COLUMN_WORD_WRAP_LIMIT) + '...'));
			unformattedText = text;
			self.text.setText(replacement);
			self.link.setVisible(MAPJS.URLHelper.containsLink(text));
			self.setStyle();
		};
		this.setText(config.text);
		this.classType = 'Idea';
		this.getNodeAttrs = function () {
			return self.attrs;
		};
		this.isVisible = function (offset) {
			var stage = self.getStage();
			return stage && stage.isRectVisible(new MAPJS.Rectangle(self.attrs.x, self.attrs.y, self.getWidth(), self.getHeight()), offset);
		};
		this.editNode = function (shouldSelectAll, deleteOnCancel) {
			self.fire(':editing');
			self.getLayer().draw();
			var canvasPosition = jQuery(self.getLayer().getCanvas().getElement()).offset(),
				ideaInput,
				onStageMoved = _.throttle(function () {
					ideaInput.css({
						top: canvasPosition.top + self.getAbsolutePosition().y,
						left: canvasPosition.left + self.getAbsolutePosition().x
					});
				}, 10),
				updateText = function (newText) {
					self.setStyle();
					self.getStage().draw();
					self.fire(':textChanged', {
						text: newText || unformattedText
					});
					ideaInput.remove();
					self.stopEditing = undefined;
					self.getStage().off('xChange yChange', onStageMoved);
				},
				onCommit = function () {
					updateText(ideaInput.val());
				},
				onCancelEdit = function () {
					updateText(unformattedText);
					if (deleteOnCancel) {
						self.fire(':request', {type: 'undo', source: 'internal'});
					}
				},
				scale = self.getStage().getScale().x || 1;
			ideaInput = jQuery('<textarea type="text" wrap="soft" class="ideaInput"></textarea>')
				.css({
					top: canvasPosition.top + self.getAbsolutePosition().y,
					left: canvasPosition.left + self.getAbsolutePosition().x,
					width: (6 + self.getWidth()) * scale,
					height: (6 + self.getHeight()) * scale,
					'padding': 3 * scale + 'px',
					'font-size': self.text.attrs.fontSize * scale + 'px',
					'line-height': '150%',
					'background-color': self.getBackground(),
					'margin': -3 * scale,
					'border-radius': self.rect.attrs.cornerRadius * scale + 'px',
					'border': self.rect.attrs.strokeWidth * (2 * scale) + 'px dashed ' + self.rect.attrs.stroke,
					'color': self.text.attrs.fill
				})
				.val(unformattedText)
				.appendTo('body')
				.keydown(function (e) {
					if (e.which === ENTER_KEY_CODE) {
						onCommit();
					} else if (e.which === ESC_KEY_CODE) {
						onCancelEdit();
					} else if (e.which === 9) {
						onCommit();
						e.preventDefault();
						self.fire(':request', {type: 'addSubIdea', source: 'keyboard'});
						return;
					} else if (e.which === 83 && (e.metaKey || e.ctrlKey)) {
						e.preventDefault();
						onCommit();
						return; /* propagate to let the environment handle ctrl+s */
					} else if (!e.shiftKey && e.which === 90 && (e.metaKey || e.ctrlKey)) {
						if (ideaInput.val() === unformattedText) {
							onCancelEdit();
						}
					}
					e.stopPropagation();
				})
				.blur(onCommit)
				.focus(function () {
					if (shouldSelectAll) {
						if (ideaInput[0].setSelectionRange) {
							ideaInput[0].setSelectionRange(0, unformattedText.length);
						} else {
							ideaInput.select();
						}
					} else if (ideaInput[0].setSelectionRange) {
						ideaInput[0].setSelectionRange(unformattedText.length, unformattedText.length);
					}
				})
				.on('input', function () {
					var text = new Kinetic.Idea({
						text: ideaInput.val()
					});
					ideaInput.width(Math.max(ideaInput.width(), text.getWidth() * scale));
					ideaInput.height(Math.max(ideaInput.height(), text.getHeight() * scale));
				});

			self.stopEditing = onCancelEdit;
			ideaInput.focus();

			self.getStage().on('xChange yChange', onStageMoved);
		};
	};
}());

Kinetic.Idea.prototype.setShadowOffset = function (offset) {
	'use strict';
	offset = this.getMMScale().x * offset;
	_.each([this.rect, this.rectbg1, this.rectbg2], function (r) {
		r.setShadowOffset([offset, offset]);
	});
};

Kinetic.Idea.prototype.getMMScale = function () {
	'use strict';
	var stage = this.getStage(),
		scale = (stage && stage.attrs && stage.attrs.scale && stage.attrs.scale.x) || (this.attrs && this.attrs.scale && this.attrs.scale.x) || 1;
	return {x: scale, y: scale};
};

Kinetic.Idea.prototype.setupShadows = function () {
	'use strict';
	var scale = this.getMMScale().x,
		isSelected = this.isSelected,
		offset = this.isCollapsed() ? 3 * scale : 4 * scale,
		normalShadow = {
			color: 'black',
			blur: 10 * scale,
			offset: [offset, offset],
			opacity: 0.4 * scale
		},
		selectedShadow = {
			color: 'black',
			blur: 0,
			offset: [offset, offset],
			opacity: 1
		},
		shadow = isSelected ? selectedShadow : normalShadow;
	_.each([this.rect, this.rectbg1, this.rectbg2], function (r) {
		r.setShadowColor(shadow.color);
		r.setShadowBlur(shadow.blur);
		r.setShadowOpacity(shadow.opacity);
		r.setShadowOffset(shadow.offset);
	});
};
Kinetic.Idea.prototype.getBackground = function () {
	'use strict';
	/*jslint newcap: true*/
	var isRoot = this.level === 1,
		defaultBg = MAPJS.defaultStyles[isRoot ? 'root' : 'nonRoot'].background,
		validColor = function (color, defaultColor) {
			if (!color) {
				return defaultColor;
			}
			var parsed = Color(color).hexString();
			return color.toUpperCase() === parsed.toUpperCase() ? color : defaultColor;
		};
	return validColor(this.mmAttr && this.mmAttr.style && this.mmAttr.style.background, defaultBg);
};
Kinetic.Idea.prototype.setStyle = function () {
	'use strict';
	/*jslint newcap: true*/
	var self = this,
		isDroppable = this.isDroppable,
		isSelected = this.isSelected,
		background = this.getBackground(),
		tintedBackground = Color(background).mix(Color('#EEEEEE')).hexString(),
		isClipVisible = this.mmAttr && this.mmAttr.attachment || false,
		padding = 8,
		clipMargin = isClipVisible ? this.clip.getClipMargin() : 0,
		rectOffset = clipMargin,
		rectIncrement = 4;
	this.clip.setVisible(isClipVisible);
	this.attrs.width = this.text.getWidth() + 2 * padding;
	this.attrs.height = this.text.getHeight() + 2 * padding + clipMargin;
	this.text.attrs.x = padding;
	this.text.attrs.y = padding + clipMargin;
	this.link.attrs.x = this.text.getWidth() + 10;
	this.link.attrs.y = this.text.getHeight() + 5 + clipMargin;
	_.each([this.rect, this.rectbg2, this.rectbg1], function (r) {
		r.attrs.width = self.text.getWidth() + 2 * padding;
		r.attrs.height = self.text.getHeight() + 2 * padding;
		r.attrs.y = rectOffset;
		rectOffset += rectIncrement;
		if (isDroppable) {
			r.attrs.stroke = '#9F4F4F';
			r.attrs.fillLinearGradientStartPoint = {x: 0, y: 0};
			r.attrs.fillLinearGradientEndPoint = {x: 100, y: 100};
			background = '#EF6F6F';
			r.attrs.fillLinearGradientColorStops = [0, background, 1, '#CF4F4F'];
		} else if (isSelected) {
			r.attrs.fillLinearGradientColorStops = [0, background, 1, background];
		} else {
			r.attrs.stroke = '#888';
			r.attrs.fillLinearGradientStartPoint = {x: 0, y: 0};
			r.attrs.fillLinearGradientEndPoint = {x: 100, y: 100};
			r.attrs.fillLinearGradientColorStops = [0, tintedBackground, 1, background];
		}
	});
	this.rectbg1.setVisible(this.isCollapsed());
	this.rectbg2.setVisible(this.isCollapsed());
	this.clip.attrs.x = this.text.getWidth() + padding;
	this.setupShadows();
	this.text.attrs.fill = MAPJS.contrastForeground(tintedBackground);
};
Kinetic.Idea.prototype.setMMAttr = function (newMMAttr) {
	'use strict';
	this.mmAttr = newMMAttr;
	this.setStyle();
	this.getLayer().draw();
};
Kinetic.Idea.prototype.getIsSelected = function () {
	'use strict';
	return this.isSelected;
};
Kinetic.Idea.prototype.isCollapsed = function () {
	'use strict';
	return this.mmAttr && this.mmAttr.collapsed || false;
};

Kinetic.Idea.prototype.setIsSelected = function (isSelected) {
	'use strict';
	this.isSelected = isSelected;
	this.setStyle();
	this.getLayer().draw();
	if (!isSelected && this.stopEditing) {
		this.stopEditing();
	}
};
Kinetic.Idea.prototype.setIsDroppable = function (isDroppable) {
	'use strict';
	this.isDroppable = isDroppable;
	this.setStyle(this.attrs);
};
Kinetic.Global.extend(Kinetic.Idea, Kinetic.Group);
<|endoftext|>


<commit_before>const SVG = require('./svg');
const ITF = require('./itf');
const { modulo11 } = require('./helpers');

class Boleto {
  /**
   * Initializes the class
   *
   * @constructor
   * @param {String} bankSlipNumber The bank slip number
   */
  constructor(bankSlipNumber) {
    this.bankSlipNumber = bankSlipNumber.replace(/[^\d]/g, '');

    if (!this.valid()) {
      throw new Error('Invalid bank slip number');
    }
  }

  /**
   * Validates whether the bank slip number is valid or not
   *
   * The validation function ensures that the bank slip number is exactly 47
   * characters long, then applies the modulo-11 algorithm to the bank slip's
   * barcode. Finally, it verifies that the result of the algorithm equals the
   * checksum digit from the bank slip number.
   *
   * @return {Boolean} Whether the bank slip number is valid or not
   */
  valid() {
    if (this.bankSlipNumber.length !== 47) return false;

    const barcodeDigits = this.barcode().split('');
    const checksum = barcodeDigits.splice(4, 1);

    return (modulo11(barcodeDigits).toString() === checksum.toString());
  }

  /**
   * Converts the printed bank slip number into the barcode number
   *
   * The bank slip's number is a rearrangement of its barcode, plus three
   * checksum digits. This function executes the inverse process and returns the
   * original arrangement of the code. Specifications can be found at
   * https://portal.febraban.org.br/pagina/3166/33/pt-br/layour-arrecadacao
   *
   * @return {String} The barcode extracted from the bank slip number
   */
  barcode() {
    return this.bankSlipNumber.replace(
      /^(\d{4})(\d{5})\d{1}(\d{10})\d{1}(\d{10})\d{1}(\d{15})$/,
      '$1$5$2$3$4',
    );
  }

  /**
   * Returns the bank slip's raw number
   *
   * @return {String} The raw bank slip number
   */
  number() {
    return this.bankSlipNumber;
  }

  /**
   * Returns the bank slip number with the usual, easy-to-read mask:
   * 00000.00000 00000.000000 00000.000000 0 00000000000000
   *
   * @return {String} The formatted bank slip number
   */
  prettyNumber() {
    return this.bankSlipNumber.replace(
      /^(\d{5})(\d{5})(\d{5})(\d{6})(\d{5})(\d{6})(\d{1})(\d{14})$/,
      '$1.$2 $3.$4 $5.$6 $7 $8',
    );
  }

  /**
   * Returns the name of the bank that issued the bank slip
   *
   * This function is able to identify the most popular or commonly used banks
   * in Brazil, but not all of them are included here.
   *
   * A comprehensive list of all Brazilian banks and their codes can be found at
   * http://www.buscabanco.org.br/AgenciasBancos.asp
   *
   * @return {String} The bank name
   */
  bank() {
    switch (this.barcode().substr(0, 3)) {
      case '001': return 'Banco do Brasil';
      case '007': return 'BNDES';
      case '033': return 'Santander';
      case '069': return 'Crefisa';
      case '077': return 'Banco Inter';
      case '102': return 'XP Investimentos';
      case '104': return 'Caixa Econômica Federal';
      case '140': return 'Easynvest';
      case '197': return 'Stone';
      case '208': return 'BTG Pactual';
      case '212': return 'Banco Original';
      case '237': return 'Bradesco';
      case '260': return 'Nu Pagamentos';
      case '341': return 'Itaú';
      case '389': return 'Banco Mercantil do Brasil';
      case '422': return 'Banco Safra';
      case '505': return 'Credit Suisse';
      case '633': return 'Banco Rendimento';
      case '652': return 'Itaú Unibanco';
      case '735': return 'Banco Neon';
      case '739': return 'Banco Cetelem';
      case '745': return 'Citibank';
      default: return 'Unknown';
    }
  }

  /**
   * Returns the currency of the bank slip
   *
   * The currency is determined by the currency code, the fourth digit of the
   * barcode. A list of values other than 9 (Brazilian Real) could not be found.
   *
   * @return {String} The currency code, symbol and decimal separator
   */
  currency() {
    switch (this.barcode()[3]) {
      case '9': return { code: 'BRL', symbol: 'R$', decimal: ',' };
      default: return 'Unknown';
    }
  }

  /**
   * Returns the verification digit of the barcode
   *
   * The barcode has its own checksum digit, which is the fifth digit of itself.
   *
   * @return {String} The checksum of the barcode
   */
  checksum() {
    return this.barcode()[4];
  }

  /**
   * Returns the date when the bank slip is due
   *
   * The portion of the barcode ranging from its sixth to its nineth digits
   * represent the number of days since the 7th of October, 1997 up to when the
   * bank slip is good to be paid. Attempting to pay a bank slip after this date
   * may incurr in extra fees.
   *
   * @return {Date} The expiration date of the bank slip
   */
  expirationDate() {
    const refDate = new Date('1997-10-07 12:00:00 GMT-0300');
    const days = this.barcode().substr(5, 4);

    return new Date(refDate.getTime() + (days * 86400000));
  }

  /**
   * Returns the bank slip's nominal amount
   *
   * @return {String} The bank slip's raw amount
   */
  amount() {
    return (this.barcode().substr(9, 10) / 100.0).toFixed(2);
  }

  /**
   * Returns the bank slip's formatted nominal amount
   *
   * @return {String} The bank slip's formatted amount
   */
  prettyAmount() {
    const currency = this.currency();

    if (currency === 'Unknown') {
      return this.amount();
    }

    return `${currency.symbol} ${this.amount().replace('.', currency.decimal)}`;
  }

  /**
   * Renders the bank slip as a child of the provided selector
   *
   * @param {String} selector The selector to the object where the SVG must be
   * appended
   *
   * @see {@link SVG#render}
   */
  toSVG(selector) {
    const stripes = ITF.encode(this.barcode());
    return new SVG(stripes).render(selector);
  }
}

module.exports = Boleto;
<commit_msg>Fix reference date<commit_after>const SVG = require('./svg');
const ITF = require('./itf');
const { modulo11 } = require('./helpers');

class Boleto {
  /**
   * Initializes the class
   *
   * @constructor
   * @param {String} bankSlipNumber The bank slip number
   */
  constructor(bankSlipNumber) {
    this.bankSlipNumber = bankSlipNumber.replace(/[^\d]/g, '');

    if (!this.valid()) {
      throw new Error('Invalid bank slip number');
    }
  }

  /**
   * Validates whether the bank slip number is valid or not
   *
   * The validation function ensures that the bank slip number is exactly 47
   * characters long, then applies the modulo-11 algorithm to the bank slip's
   * barcode. Finally, it verifies that the result of the algorithm equals the
   * checksum digit from the bank slip number.
   *
   * @return {Boolean} Whether the bank slip number is valid or not
   */
  valid() {
    if (this.bankSlipNumber.length !== 47) return false;

    const barcodeDigits = this.barcode().split('');
    const checksum = barcodeDigits.splice(4, 1);

    return (modulo11(barcodeDigits).toString() === checksum.toString());
  }

  /**
   * Converts the printed bank slip number into the barcode number
   *
   * The bank slip's number is a rearrangement of its barcode, plus three
   * checksum digits. This function executes the inverse process and returns the
   * original arrangement of the code. Specifications can be found at
   * https://portal.febraban.org.br/pagina/3166/33/pt-br/layour-arrecadacao
   *
   * @return {String} The barcode extracted from the bank slip number
   */
  barcode() {
    return this.bankSlipNumber.replace(
      /^(\d{4})(\d{5})\d{1}(\d{10})\d{1}(\d{10})\d{1}(\d{15})$/,
      '$1$5$2$3$4',
    );
  }

  /**
   * Returns the bank slip's raw number
   *
   * @return {String} The raw bank slip number
   */
  number() {
    return this.bankSlipNumber;
  }

  /**
   * Returns the bank slip number with the usual, easy-to-read mask:
   * 00000.00000 00000.000000 00000.000000 0 00000000000000
   *
   * @return {String} The formatted bank slip number
   */
  prettyNumber() {
    return this.bankSlipNumber.replace(
      /^(\d{5})(\d{5})(\d{5})(\d{6})(\d{5})(\d{6})(\d{1})(\d{14})$/,
      '$1.$2 $3.$4 $5.$6 $7 $8',
    );
  }

  /**
   * Returns the name of the bank that issued the bank slip
   *
   * This function is able to identify the most popular or commonly used banks
   * in Brazil, but not all of them are included here.
   *
   * A comprehensive list of all Brazilian banks and their codes can be found at
   * http://www.buscabanco.org.br/AgenciasBancos.asp
   *
   * @return {String} The bank name
   */
  bank() {
    switch (this.barcode().substr(0, 3)) {
      case '001': return 'Banco do Brasil';
      case '007': return 'BNDES';
      case '033': return 'Santander';
      case '069': return 'Crefisa';
      case '077': return 'Banco Inter';
      case '102': return 'XP Investimentos';
      case '104': return 'Caixa Econômica Federal';
      case '140': return 'Easynvest';
      case '197': return 'Stone';
      case '208': return 'BTG Pactual';
      case '212': return 'Banco Original';
      case '237': return 'Bradesco';
      case '260': return 'Nu Pagamentos';
      case '341': return 'Itaú';
      case '389': return 'Banco Mercantil do Brasil';
      case '422': return 'Banco Safra';
      case '505': return 'Credit Suisse';
      case '633': return 'Banco Rendimento';
      case '652': return 'Itaú Unibanco';
      case '735': return 'Banco Neon';
      case '739': return 'Banco Cetelem';
      case '745': return 'Citibank';
      default: return 'Unknown';
    }
  }

  /**
   * Returns the currency of the bank slip
   *
   * The currency is determined by the currency code, the fourth digit of the
   * barcode. A list of values other than 9 (Brazilian Real) could not be found.
   *
   * @return {String} The currency code, symbol and decimal separator
   */
  currency() {
    switch (this.barcode()[3]) {
      case '9': return { code: 'BRL', symbol: 'R$', decimal: ',' };
      default: return 'Unknown';
    }
  }

  /**
   * Returns the verification digit of the barcode
   *
   * The barcode has its own checksum digit, which is the fifth digit of itself.
   *
   * @return {String} The checksum of the barcode
   */
  checksum() {
    return this.barcode()[4];
  }

  /**
   * Returns the date when the bank slip is due
   *
   * The portion of the barcode ranging from its sixth to its nineth digits
   * represent the number of days since the 7th of October, 1997 up to when the
   * bank slip is good to be paid. Attempting to pay a bank slip after this date
   * may incurr in extra fees.
   *
   * @return {Date} The expiration date of the bank slip
   */
  expirationDate() {
    const refDate = new Date(876236400000); // 1997-10-07 12:00:00 GMT-0300
    const days = this.barcode().substr(5, 4);

    return new Date(refDate.getTime() + (days * 86400000));
  }

  /**
   * Returns the bank slip's nominal amount
   *
   * @return {String} The bank slip's raw amount
   */
  amount() {
    return (this.barcode().substr(9, 10) / 100.0).toFixed(2);
  }

  /**
   * Returns the bank slip's formatted nominal amount
   *
   * @return {String} The bank slip's formatted amount
   */
  prettyAmount() {
    const currency = this.currency();

    if (currency === 'Unknown') {
      return this.amount();
    }

    return `${currency.symbol} ${this.amount().replace('.', currency.decimal)}`;
  }

  /**
   * Renders the bank slip as a child of the provided selector
   *
   * @param {String} selector The selector to the object where the SVG must be
   * appended
   *
   * @see {@link SVG#render}
   */
  toSVG(selector) {
    const stripes = ITF.encode(this.barcode());
    return new SVG(stripes).render(selector);
  }
}

module.exports = Boleto;
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'
import Dropzone from 'react-dropzone'
import { Glyphicon } from 'react-bootstrap'
import { shell } from 'electron'
import { observer, inject } from 'mobx-react'
import compose from 'recompose/compose'

import regularStyles from './areaLinks.css'
import pdfStyles from './areaLinksPdf.css'

const enhance = compose(
  inject('store'),
  observer
)

const AreaLinks = ({ store, links }) => {
  const { linkNewCreate, linkRemove } = store
  const { activeId } = store.geschaefte
  const path = store.history.location.pathname
  const isPrintPreview = path === '/geschaeftPdf'
  const styles = isPrintPreview ? pdfStyles : regularStyles

  const onDrop = files =>
    linkNewCreate(activeId, files[0].path)

  return (

        Links

        {
          links.map(link =>
            <div
              key={`${link.idGeschaeft}${link.url}`}
              className={styles.fields}
            >

                 {
                    event.preventDefault()
                    shell.openItem(link.url)
                  }}
                >
                  {link.url}

                <Glyphicon
                  glyph="remove-circle"
                  onClick={() => linkRemove(activeId, link.url)}
                  className={styles.removeGlyphicon}
                  title="Link entfernen"
                />

          )
        }

        <Dropzone
          onDrop={onDrop}
          className={styles.dropzone}
        >

Datei hierhin ziehen...

...oder klicken, um sie zu wählen.

        </Dropzone>

  )
}

AreaLinks.displayName = 'AreaLinks'

AreaLinks.propTypes = {
  links: PropTypes.array.isRequired,
  store: PropTypes.object.isRequired,
}

export default enhance(AreaLinks)
<commit_msg>update dropzone<commit_after>import React, { PropTypes } from 'react'
import Dropzone from 'react-dropzone'
import { Glyphicon } from 'react-bootstrap'
import { shell } from 'electron'
import { observer, inject } from 'mobx-react'
import compose from 'recompose/compose'
import styled from 'styled-components'

import regularStyles from './areaLinks.css'
import pdfStyles from './areaLinksPdf.css'

const DropzoneInnerDiv = styled.div`
  width: 100%;
  height: 100%;
  border-width: 2px;
  border-color: #666;
  border-style: dashed;
  border-radius: 5px;
  padding: 5px;
`

const enhance = compose(
  inject('store'),
  observer
)

const AreaLinks = ({ store, links }) => {
  const { linkNewCreate, linkRemove } = store
  const { activeId } = store.geschaefte
  const path = store.history.location.pathname
  const isPrintPreview = path === '/geschaeftPdf'
  const styles = isPrintPreview ? pdfStyles : regularStyles

  const onDrop = files =>
    linkNewCreate(activeId, files[0].path)

  return (

        Links

        {
          links.map(link =>
            <div
              key={`${link.idGeschaeft}${link.url}`}
              className={styles.fields}
            >

                 {
                    event.preventDefault()
                    shell.openItem(link.url)
                  }}
                >
                  {link.url}

                <Glyphicon
                  glyph="remove-circle"
                  onClick={() => linkRemove(activeId, link.url)}
                  className={styles.removeGlyphicon}
                  title="Link entfernen"
                />

          )
        }

        <Dropzone
          onDrop={onDrop}
          style={{
            width: '100%',
            height: '100%',
            borderColor: 'transparent',
          }}
        >
          {
            ({ isDragActive, isDragReject }) => {
              if (isDragActive) {
                return (
                  <DropzoneInnerDiv>

jetzt fallen lassen...

                  </DropzoneInnerDiv>
                )
              }
              if (isDragReject) {
                return (
                  <DropzoneInnerDiv>

Hm. Da ging etwas schief :-(

                  </DropzoneInnerDiv>
                )
              }
              return (
                <DropzoneInnerDiv>

Datei hierhin ziehen...

...oder klicken, um sie zu wählen.

                </DropzoneInnerDiv>
              )
            }
          }
        </Dropzone>

  )
}

AreaLinks.displayName = 'AreaLinks'

AreaLinks.propTypes = {
  links: PropTypes.array.isRequired,
  store: PropTypes.object.isRequired,
}

export default enhance(AreaLinks)
<|endoftext|>


<commit_before>Lizard.Views.MapLegend = L.Control.extend({
  options: {
    collapsed: true,
    position: 'bottomleft',
    autoZIndex: true
  },

  initialize: function (workspace, options) {
    L.setOptions(this, options);

    this._lastZIndex = 0;
    this._handlingClick = false;
    this.workspace = workspace;
    this._expanded = false;

  },

  onAdd: function (map) {
    this._initLayout();
    //this._update();
    return this._container;

  },

  onRemove: function (map) {
  },

  _initLayout: function () {
    var className = 'leaflet-control-legend',
      container = this._container = L.DomUtil.create('div', className);

    if (!L.Browser.touch) {
      L.DomEvent.disableClickPropagation(container);
      L.DomEvent.on(container, 'mousewheel', L.DomEvent.stopPropagation);
    } else {
      L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
    }

    if (this.options.collapsed) {
      L.DomEvent
        .on(container, 'click', this._toggle, this)
      var link = this._layersLink = L.DomUtil.create('i', "leaflet-control-legend-icon icon-list icon-white ", container);
      link.href = '#';
      link.title = 'Legenda';

      if (L.Browser.touch) {
        L.DomEvent
          .on(link, 'click', L.DomEvent.stopPropagation)
          .on(link, 'click', L.DomEvent.preventDefault)
          .on(link, 'click', this._toggle, this);
      } else {
        L.DomEvent.on(link, 'focus', this._toggle, this);
      }

      this._map.on('movestart', this._toggle, this);
      // TODO keyboard accessibility
    } else {
      this._toggle();
    }

  },
  _toggle: function () {
    if (this._expanded) {
      this._container.className = this._container.className.replace(' leaflet-control-legend-expanded', '');
      this._expanded = false;
    } else {
      L.DomUtil.addClass(this._container, 'leaflet-control-legend-expanded');
      this._expanded = true;
    }
  }
});
<commit_msg>Cleaning up<commit_after>Lizard.Views.MapLegend = L.Control.extend({
  options: {
    collapsed: true,
    position: 'bottomleft',
    autoZIndex: true
  },

  initialize: function (workspace, options) {
    L.setOptions(this, options);

    this._lastZIndex = 0;
    this._handlingClick = false;
    this.workspace = workspace;
    this._expanded = false;

  },

  onAdd: function (map) {
    this._initLayout();
    //this._update();
    return this._container;

  },

  onRemove: function (map) {
  },

  _initLayout: function () {
    var className = 'leaflet-control-legend',
      container = this._container = L.DomUtil.create('div', className);

    if (!L.Browser.touch) {
      L.DomEvent.disableClickPropagation(container);
      L.DomEvent.on(container, 'mousewheel', L.DomEvent.stopPropagation);
    } else {
      L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
    }

    if (this.options.collapsed) {
      L.DomEvent
        .on(container, 'click', this._toggle, this);
      var link = this._layersLink = L.DomUtil.create('i', "leaflet-control-legend-icon icon-list icon-white ", container);
      link.href = '#';
      link.title = 'Legenda';

      if (L.Browser.touch) {
        L.DomEvent
          .on(link, 'click', L.DomEvent.stopPropagation)
          .on(link, 'click', L.DomEvent.preventDefault)
          .on(link, 'click', this._toggle, this);
      } else {
        L.DomEvent.on(link, 'focus', this._toggle, this);
      }

      this._map.on('movestart', this._toggle, this);
      // TODO keyboard accessibility
    } else {
      this._toggle();
    }

  },
  _toggle: function () {
    if (this._expanded) {
      this._container.className = this._container.className.replace(' leaflet-control-legend-expanded', '');
      this._expanded = false;
    } else {
      L.DomUtil.addClass(this._container, 'leaflet-control-legend-expanded');
      this._expanded = true;
    }
  }
});
<|endoftext|>


<commit_before>// @flow

import React from 'react';
import Relay from 'react-relay/classic';

import Link from './link';
import Icon from 'app/components/shared/Icon';

type Props = {
  viewer?: {
    unreadChangelogs?: {
      count: number
    }
  },
  relay: Object
};

class Footer extends React.PureComponent<Props> {
  componentDidMount() {
    this.props.relay.setVariables({ isMounted: true });
  }

  render() {
    let changelogBadge;
    // Viewer is not supplied when rendered for an anonymous user
    if (this.props.viewer && this.props.viewer.unreadChangelogs && this.props.viewer.unreadChangelogs.count > 0) {
      changelogBadge = (
        <span className={`inline-block bg-dark-gray hover-lime-child white rounded ml1 small p1 line-height-1`}>{this.props.viewer.unreadChangelogs.count}
      );
    }

    return (

            <Link href="/home">Home</Link>
            <Link href="/changelog">
              Changelog{changelogBadge}
            </Link>
            <Link href="/blog">Blog</Link>
            <Link href="/docs">Docs</Link>
            <Link href="https://github.com/buildkite/feedback/issues">Feedback</Link>
            <Link href="/privacy-policy">Privacy</Link>
            <Link href="/terms-of-service">Terms</Link>
            <Link href="mailto:support@buildkite.com">Support</Link>
            <Link href="https://buildkitestatus.com/">System Status</Link>

            <a href="http://twitter.com/buildkite" className={`btn hover-lime px1`}><Icon icon="twitter" />
            <a href="https://github.com/buildkite" className={`btn hover-lime px1`}><Icon icon="github" />

    );
  }
}

export default Relay.createContainer(Footer, {
  initialVariables: {
    isMounted: false
  },

  fragments: {
    viewer: () => Relay.QL`
      fragment on Viewer {
        unreadChangelogs: changelogs(read: false) @include(if: $isMounted) {
          count
        }
      }
    `
  }
});
<commit_msg>Feature forum link in footer<commit_after>// @flow

import React from 'react';
import Relay from 'react-relay/classic';

import Link from './link';
import Icon from 'app/components/shared/Icon';

type Props = {
  viewer?: {
    unreadChangelogs?: {
      count: number
    }
  },
  relay: Object
};

class Footer extends React.PureComponent<Props> {
  componentDidMount() {
    this.props.relay.setVariables({ isMounted: true });
  }

  render() {
    let changelogBadge;
    // Viewer is not supplied when rendered for an anonymous user
    if (this.props.viewer && this.props.viewer.unreadChangelogs && this.props.viewer.unreadChangelogs.count > 0) {
      changelogBadge = (
        <span className={`inline-block bg-dark-gray hover-lime-child white rounded ml1 small p1 line-height-1`}>{this.props.viewer.unreadChangelogs.count}
      );
    }

    return (

            <Link href="/home">Home</Link>
            <Link href="/changelog">
              Changelog{changelogBadge}
            </Link>
            <Link href="/blog">Blog</Link>
            <Link href="/docs">Docs</Link>
            <Link href="https://github.com/buildkite/feedback/issues">Feedback</Link>
            <Link href="/privacy-policy">Privacy</Link>
            <Link href="/terms-of-service">Terms</Link>
            <Link href="https://forum.buildkite.community/">Community Forum</Link>
            <Link href="https://buildkitestatus.com/">System Status</Link>

            <a href="http://twitter.com/buildkite" className={`btn hover-lime px1`}><Icon icon="twitter" />
            <a href="https://github.com/buildkite" className={`btn hover-lime px1`}><Icon icon="github" />

    );
  }
}

export default Relay.createContainer(Footer, {
  initialVariables: {
    isMounted: false
  },

  fragments: {
    viewer: () => Relay.QL`
      fragment on Viewer {
        unreadChangelogs: changelogs(read: false) @include(if: $isMounted) {
          count
        }
      }
    `
  }
});
<|endoftext|>


<commit_before>(function () {
    'use strict';

    angular.module('main.directives')
        .directive('choropleth', ['d3', 'color_convert', function (d3, cc) {
            return {
                restrict: 'EA',
                scope: {
                    data: "=",
                    modeList: "=",
                    activeMode: "="
                },
                link: function (scope, iElement, iAttrs) {

                    var width = 900,
                        height = 480,

                    //zoom variables
                        centered,
                        active;

                    var quantize = d3.scale.quantize()
                        .domain([0, .15])
                        .range(d3.range(9).map(function(i) { return "q" + i + "-9"; }));

                    var projection = d3.geo.albersUsa()
                        .scale(1280)
                        .translate([width / 2, height / 2]);

                    var path = d3.geo.path()
                        .projection(projection);

                    var zoom = d3.behavior.zoom()
                        .center([width/2, height/2])
                        .scaleExtent([.8,.8])
                        .on("zoom", zoomed);

                    function zoomed() {
                        container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
                    }

                    var svg = d3.select(iElement[0])
                            .append("svg")
                            .attr("width", width)
                            .attr("height", height)
                            .append('g')
                        ;

                    var container = svg.append("g");

                    queue()
                        .defer(d3.json, "/data/all-id.json")
                        .defer(d3.csv, "/data/zip3.csv")
                        .defer(d3.json, "/data/stateAgr.json")
                        .await(ready);

                    function ready(error, us, zc, sa) {
                        if (error) throw error;

                        var zipCodes = {};

                        zc.forEach(function(d) { zipCodes[d.Id] = d.Name; });

                        var cnt = 0;
                        container.append("g").attr("class", "allZones");

                        d3.select(".allZones")
                            .append("g")
                            .attr("class", "zones")
                            .selectAll("path")
                            .data(topojson.feature(us, us.objects.zip3).features)
                            .enter().append("path")
                            .attr("stroke-width", 1)
                            .attr("stroke", "white")
                            .attr("class", function(d) {
                                var location_name = zipCodes[d.properties.ZIP];
                                if(typeof location_name == "string"){
                                    location_name = location_name.substr(location_name.length-2, 2);
                                }
                                return "cZones " + location_name + " " + d.properties.ZIP })
                            .attr("loc", function(d) {
                                return zipCodes[d.properties.ZIP] })
                            .attr("d", path)
                            //.style("z-index", 0)
                            .on("click", clicked)
                        ;

                        d3.select(".allZones")
                            .append("g")
                            .attr("class", "stateZones")
                            .selectAll("path")
                            .data(topojson.feature(us, us.objects.tl_2010_us_state10).features)
                            .enter().append("path")
                            //.style("z-index", 1)
                            .attr("class", "stateZone")
                            .attr("id", function(d){return d.properties.STUSPS10})
                            .attr("d", path)
                            .attr("ts", function(d){return sa[d.properties.STUSPS10].total_streams})
                            .attr("tc", function(d){return sa[d.properties.STUSPS10].total_customers})
                            .attr("pop", function(d){return sa[d.properties.STUSPS10].population})
                            .style("fill", function(d){
                                var saturation = sa[d.properties.STUSPS10].total_streams / 30000000 * 100;
                                return "hsl(37, " + saturation + "%, 55%)";
                            })
                            .on("click", clicked)
                            //.on("mouseover", hovering)
                            //.on("mouseout", notHovering)
                        ;

                        container.append("path")
                            .datum(topojson.mesh(us, us.objects.tl_2010_us_state10, function(a, b) { return a !== b; }))
                            .attr("class", "states")
                            .attr("d", path);

                        container
                            .transition()
                            .duration(500)
                            .attr("transform", function(){
                                var translate = "50,50";
                                var scale = ".8,.8";
                                return "translate(" + translate + ")scale(" + scale + ")";
                            })
                        ;
                    }

                    function clicked(d){

                        var x, y, k;

                        if (d && centered !== d && this.getAttribute("id") != null) {
                            var centroid = path.centroid(d);
                            x = centroid[0];
                            y = centroid[1];
                            k = 4;
                            centered = d;
                            active = this.getAttribute("id");

                            $("."+active)
                                .attr("hidden", false)
                            ;

                            $("#"+active)
                                .attr("hidden", true)
                            ;
                        } else {
                            x = width / 2;
                            y = height / 2;
                            k = 1;
                            centered = null;

                            $("."+active)
                                .attr("hidden", true)
                            ;

                            $("#"+active)
                                .attr("hidden", false)
                            ;
                            active = null;
                        }

                        container.selectAll(".zones path")
                            .classed("active", centered && function(d) { return d === centered; });

                        container.selectAll("path")
                            .transition()
                            .duration(750)
                            .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")")
                            .style("stroke-width", 1.5 / k + "px");
                    }

                    // define render function
                    function render(data){
                        if(data != undefined){
                            for(var zip in data){
                                if(  !/^[0-9]+$/.test(zip)  || zip == ""){
                                    continue;
                                }
                                if ($("."+zip)){

                                    var opac = "1.0";
                                    var value = data[zip].streams;
                                    if(value < 1){
                                        opac = "0.0";
                                    }
                                    else if(value >= 1 && value < 9999){
                                        opac = "0.3";
                                    }
                                    else if(value >= 10000 && value < 49999){
                                        opac = "0.5";
                                    }
                                    else if(value >= 50000 && value < 99999){
                                        opac = "0.8";
                                    }

                                    $("."+zip)
                                        .attr("style", "opacity:"+ opac + "; fill:grey; z-index:0")
                                        .attr("hidden", true)
                                        .attr("streams", value)
                                        .hover(function() {
                                            $(this).css("fill","gold")
                                        }, function(){
                                            $(this).css("fill","grey")
                                        });
                                }
                            }
                        }
                    }

                    //update the color of the choropleth to the corresponding color for the mode
                    function updateMode(c){
                        //get color value from the mode
                        var valueStr = scope.modeList[c]["color"];
                        var values = valueStr.split(",");

                        //change color of map
                        d3.selectAll('.stateZone')
                            .style("fill", function(d){
                                var streams = d3.select(this).attr("ts");
                                var customers = d3.select(this).attr("tc");
                                var population = d3.select(this).attr("pop");

                                var saturation = streams / 30000000 * 100;
                                return "hsl("+ values[0] +", " + saturation + "%, " + values[2]*100 + "%)";
                            })
                        ;
                    }

                    scope.$watch('activeMode', function(newVals, oldVals) {
                        return updateMode(newVals);
                    });

                    scope.$watch('data', function(newVals, oldVals) {
                        return render(newVals);
                    });
                }
            }
        }]);
}());<commit_msg>fixed choro dir<commit_after>(function () {
    'use strict';

    angular.module('main.directives')
        .directive('choropleth', ['d3', 'color_convert', function (d3, cc) {
            return {
                restrict: 'EA',
                scope: {
                    data: "=",
                    modeList: "=",
                    activeMode: "="
                },
                link: function (scope, iElement, iAttrs) {

                    var width = 900,
                        height = 480,

                    //zoom variables
                        centered,
                        active;

                    var quantize = d3.scale.quantize()
                        .domain([0, .15])
                        .range(d3.range(9).map(function(i) { return "q" + i + "-9"; }));

                    var projection = d3.geo.albersUsa()
                        .scale(1280)
                        .translate([width / 2, height / 2]);

                    var path = d3.geo.path()
                        .projection(projection);

                    var zoom = d3.behavior.zoom()
                        .center([width/2, height/2])
                        .scaleExtent([.8,.8])
                        .on("zoom", zoomed);

                    function zoomed() {
                        container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
                    }

                    var svg = d3.select(iElement[0])
                            .append("svg")
                            .attr("width", width)
                            .attr("height", height)
                            .append('g')
                        ;

                    var container = svg.append("g");

                    queue()
                        .defer(d3.json, "data/all-id.json")
                        .defer(d3.csv, "data/zip3.csv")
                        .defer(d3.json, "data/stateAgr.json")
                        .await(ready);

                    function ready(error, us, zc, sa) {
                        if (error) throw error;

                        var zipCodes = {};

                        zc.forEach(function(d) { zipCodes[d.Id] = d.Name; });

                        var cnt = 0;
                        container.append("g").attr("class", "allZones");

                        d3.select(".allZones")
                            .append("g")
                            .attr("class", "zones")
                            .selectAll("path")
                            .data(topojson.feature(us, us.objects.zip3).features)
                            .enter().append("path")
                            .attr("stroke-width", 1)
                            .attr("stroke", "white")
                            .attr("class", function(d) {
                                var location_name = zipCodes[d.properties.ZIP];
                                if(typeof location_name == "string"){
                                    location_name = location_name.substr(location_name.length-2, 2);
                                }
                                return "cZones " + location_name + " " + d.properties.ZIP })
                            .attr("loc", function(d) {
                                return zipCodes[d.properties.ZIP] })
                            .attr("d", path)
                            //.style("z-index", 0)
                            .on("click", clicked)
                        ;

                        d3.select(".allZones")
                            .append("g")
                            .attr("class", "stateZones")
                            .selectAll("path")
                            .data(topojson.feature(us, us.objects.tl_2010_us_state10).features)
                            .enter().append("path")
                            //.style("z-index", 1)
                            .attr("class", "stateZone")
                            .attr("id", function(d){return d.properties.STUSPS10})
                            .attr("d", path)
                            .attr("ts", function(d){return sa[d.properties.STUSPS10].total_streams})
                            .attr("tc", function(d){return sa[d.properties.STUSPS10].total_customers})
                            .attr("pop", function(d){return sa[d.properties.STUSPS10].population})
                            .style("fill", function(d){
                                var saturation = sa[d.properties.STUSPS10].total_streams / 30000000 * 100;
                                return "hsl(37, " + saturation + "%, 55%)";
                            })
                            .on("click", clicked)
                            //.on("mouseover", hovering)
                            //.on("mouseout", notHovering)
                        ;

                        container.append("path")
                            .datum(topojson.mesh(us, us.objects.tl_2010_us_state10, function(a, b) { return a !== b; }))
                            .attr("class", "states")
                            .attr("d", path);

                        container
                            .transition()
                            .duration(500)
                            .attr("transform", function(){
                                var translate = "50,50";
                                var scale = ".8,.8";
                                return "translate(" + translate + ")scale(" + scale + ")";
                            })
                        ;
                    }

                    function clicked(d){

                        var x, y, k;

                        if (d && centered !== d && this.getAttribute("id") != null) {
                            var centroid = path.centroid(d);
                            x = centroid[0];
                            y = centroid[1];
                            k = 4;
                            centered = d;
                            active = this.getAttribute("id");

                            $("."+active)
                                .attr("hidden", false)
                            ;

                            $("#"+active)
                                .attr("hidden", true)
                            ;
                        } else {
                            x = width / 2;
                            y = height / 2;
                            k = 1;
                            centered = null;

                            $("."+active)
                                .attr("hidden", true)
                            ;

                            $("#"+active)
                                .attr("hidden", false)
                            ;
                            active = null;
                        }

                        container.selectAll(".zones path")
                            .classed("active", centered && function(d) { return d === centered; });

                        container.selectAll("path")
                            .transition()
                            .duration(750)
                            .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(" + k + ")translate(" + -x + "," + -y + ")")
                            .style("stroke-width", 1.5 / k + "px");
                    }

                    // define render function
                    function render(data){
                        if(data != undefined){
                            for(var zip in data){
                                if(  !/^[0-9]+$/.test(zip)  || zip == ""){
                                    continue;
                                }
                                if ($("."+zip)){

                                    var opac = "1.0";
                                    var value = data[zip].streams;
                                    if(value < 1){
                                        opac = "0.0";
                                    }
                                    else if(value >= 1 && value < 9999){
                                        opac = "0.3";
                                    }
                                    else if(value >= 10000 && value < 49999){
                                        opac = "0.5";
                                    }
                                    else if(value >= 50000 && value < 99999){
                                        opac = "0.8";
                                    }

                                    $("."+zip)
                                        .attr("style", "opacity:"+ opac + "; fill:grey; z-index:0")
                                        .attr("hidden", true)
                                        .attr("streams", value)
                                        .hover(function() {
                                            $(this).css("fill","gold")
                                        }, function(){
                                            $(this).css("fill","grey")
                                        });
                                }
                            }
                        }
                    }

                    //update the color of the choropleth to the corresponding color for the mode
                    function updateMode(c){
                        //get color value from the mode
                        var valueStr = scope.modeList[c]["color"];
                        var values = valueStr.split(",");

                        //change color of map
                        d3.selectAll('.stateZone')
                            .style("fill", function(d){
                                var streams = d3.select(this).attr("ts");
                                var customers = d3.select(this).attr("tc");
                                var population = d3.select(this).attr("pop");

                                var saturation = streams / 30000000 * 100;
                                return "hsl("+ values[0] +", " + saturation + "%, " + values[2]*100 + "%)";
                            })
                        ;
                    }

                    scope.$watch('activeMode', function(newVals, oldVals) {
                        return updateMode(newVals);
                    });

                    scope.$watch('data', function(newVals, oldVals) {
                        return render(newVals);
                    });
                }
            }
        }]);
}());<|endoftext|>