<commit_before>goog.provide('interactionbtngroup');

goog.require('go_decorateinteraction_service');
goog.require('go_map_directive');
goog.require('ol.FeatureOverlay');
goog.require('ol.Map');
goog.require('ol.View2D');
goog.require('ol.interaction.Draw');
goog.require('ol.layer.Tile');
goog.require('ol.source.MapQuest');

(function() {
  var module = angular.module('app', ['go']);

  module.controller('MainController', ['$scope', 'goDecorateInteraction',
    /**
     * @param {angular.Scope} $scope Scope.
     * @param {go.DecorateInteraction} goDecorateInteraction Decorate
     *     interaction service.
     */
    function($scope, goDecorateInteraction) {

      var source = new ol.source.Vector();

      var vector = new ol.layer.Vector({
        source: source,
        style: new ol.style.Style({
          fill: new ol.style.Fill({
            color: 'rgba(255, 255, 255, 0.2)'
          }),
          stroke: new ol.style.Stroke({
            color: '#ffcc33',
            width: 2
          }),
          image: new ol.style.Circle({
            radius: 7,
            fill: new ol.style.Fill({
              color: '#ffcc33'
            })
          })
        })
      });

      /** @type {ol.Map} */
      $scope.map = new ol.Map({
        layers: [
          new ol.layer.Tile({
            source: new ol.source.MapQuest({layer: 'sat'})
          }),
          vector
        ],
        view: new ol.View2D({
          center: [-10997148, 4569099],
          zoom: 4
        })
      });

      /** @type {ol.interaction.Draw} */
      $scope.drawPolygon = new ol.interaction.Draw(
          /** @type {olx.interaction.DrawOptions} */ ({
            type: 'Polygon',
            source: source
          }));
      goDecorateInteraction($scope.drawPolygon, $scope.map);

      /** @type {ol.interaction.Draw} */
      $scope.drawPoint = new ol.interaction.Draw(
          /** @type {olx.interaction.DrawOptions} */ ({
            type: 'Point',
            source: source
          }));
      goDecorateInteraction($scope.drawPoint, $scope.map);

      /** @type {ol.interaction.Draw} */
      $scope.drawLine = new ol.interaction.Draw(
          /** @type {olx.interaction.DrawOptions} */ ({
            type: 'LineString',
            source: source
          }));
      goDecorateInteraction($scope.drawLine, $scope.map);
    }]);

  module.directive('goBtnGroup', function() {
    return {
      restrict: 'A',
      controller:
          function() {
            /**
             * @type {Array.<{scope:angular.Scope,
             *                setter:function((!angular.Scope), *)}>}
             */
            var buttons = [];

            /**
             * @param {angular.Scope} btnScope Scope of the goBtn directive.
             */
            this.activate = function(btnScope) {
              goog.array.forEach(buttons, function(b) {
                if (b.scope != btnScope) {
                  b.setter(b.scope, false);
                }
              });
            };

            /**
             * @param {angular.Scope} btnScope Scope of the goBtn directive.
             * @param {function((!angular.Scope), *)} ngModelSet Setter.
             */
            this.addButton = function(btnScope, ngModelSet) {
              buttons.push({
                scope: btnScope,
                setter: ngModelSet
              });
            };
          }
    };
  })
    .directive('goBtn', ['$parse',
        function($parse) {
          return {
            require: ['^goBtnGroup', 'ngModel'],
            restrict: 'A',
            scope: true,
            link:
                /**
                 * @param {angular.Scope} scope Scope.
                 * @param {angular.JQLite} element Element.
                 * @param {angular.Attributes} attrs Attributes.
                 * @param {!Array.<!Object>} ctrls Controllers.
                 */
                function(scope, element, attrs, ctrls) {
                  var buttonsCtrl = ctrls[0];
                  var ngModelCtrl = ctrls[1];

                  var ngModelGet = $parse(attrs['ngModel']);
                  var ngModelSet = ngModelGet.assign;

                  buttonsCtrl.addButton(scope, ngModelSet);

                  //ui->model
                  element.bind('click', function() {
                    scope.$apply(function() {
                      ngModelCtrl.$setViewValue(!ngModelCtrl.$viewValue);
                      ngModelCtrl.$render();
                    });
                  });

                  //model -> UI
                  ngModelCtrl.$render = function() {
                    if (ngModelCtrl.$viewValue) {
                      buttonsCtrl.activate(scope);
                    }
                    element.toggleClass('active', ngModelCtrl.$viewValue);
                  };
                }
          };
        }]);
})();
<commit_msg>Do not use goog in examples<commit_after>goog.provide('interactionbtngroup');

goog.require('go_decorateinteraction_service');
goog.require('go_map_directive');
goog.require('ol.FeatureOverlay');
goog.require('ol.Map');
goog.require('ol.View2D');
goog.require('ol.interaction.Draw');
goog.require('ol.layer.Tile');
goog.require('ol.source.MapQuest');

(function() {
  var module = angular.module('app', ['go']);

  module.controller('MainController', ['$scope', 'goDecorateInteraction',
    /**
     * @param {angular.Scope} $scope Scope.
     * @param {go.DecorateInteraction} goDecorateInteraction Decorate
     *     interaction service.
     */
    function($scope, goDecorateInteraction) {

      var source = new ol.source.Vector();

      var vector = new ol.layer.Vector({
        source: source,
        style: new ol.style.Style({
          fill: new ol.style.Fill({
            color: 'rgba(255, 255, 255, 0.2)'
          }),
          stroke: new ol.style.Stroke({
            color: '#ffcc33',
            width: 2
          }),
          image: new ol.style.Circle({
            radius: 7,
            fill: new ol.style.Fill({
              color: '#ffcc33'
            })
          })
        })
      });

      /** @type {ol.Map} */
      $scope.map = new ol.Map({
        layers: [
          new ol.layer.Tile({
            source: new ol.source.MapQuest({layer: 'sat'})
          }),
          vector
        ],
        view: new ol.View2D({
          center: [-10997148, 4569099],
          zoom: 4
        })
      });

      /** @type {ol.interaction.Draw} */
      $scope.drawPolygon = new ol.interaction.Draw(
          /** @type {olx.interaction.DrawOptions} */ ({
            type: 'Polygon',
            source: source
          }));
      goDecorateInteraction($scope.drawPolygon, $scope.map);

      /** @type {ol.interaction.Draw} */
      $scope.drawPoint = new ol.interaction.Draw(
          /** @type {olx.interaction.DrawOptions} */ ({
            type: 'Point',
            source: source
          }));
      goDecorateInteraction($scope.drawPoint, $scope.map);

      /** @type {ol.interaction.Draw} */
      $scope.drawLine = new ol.interaction.Draw(
          /** @type {olx.interaction.DrawOptions} */ ({
            type: 'LineString',
            source: source
          }));
      goDecorateInteraction($scope.drawLine, $scope.map);
    }]);

  module.directive('goBtnGroup', function() {
    return {
      restrict: 'A',
      controller:
          function() {
            /**
             * @type {Array.<{scope:angular.Scope,
             *                setter:function((!angular.Scope), *)}>}
             */
            var buttons = [];

            /**
             * @param {angular.Scope} btnScope Scope of the goBtn directive.
             */
            this.activate = function(btnScope) {
              buttons.forEach(function(b) {
                if (b.scope != btnScope) {
                  b.setter(b.scope, false);
                }
              });
            };

            /**
             * @param {angular.Scope} btnScope Scope of the goBtn directive.
             * @param {function((!angular.Scope), *)} ngModelSet Setter.
             */
            this.addButton = function(btnScope, ngModelSet) {
              buttons.push({
                scope: btnScope,
                setter: ngModelSet
              });
            };
          }
    };
  })
    .directive('goBtn', ['$parse',
        function($parse) {
          return {
            require: ['^goBtnGroup', 'ngModel'],
            restrict: 'A',
            scope: true,
            link:
                /**
                 * @param {angular.Scope} scope Scope.
                 * @param {angular.JQLite} element Element.
                 * @param {angular.Attributes} attrs Attributes.
                 * @param {!Array.<!Object>} ctrls Controllers.
                 */
                function(scope, element, attrs, ctrls) {
                  var buttonsCtrl = ctrls[0];
                  var ngModelCtrl = ctrls[1];

                  var ngModelGet = $parse(attrs['ngModel']);
                  var ngModelSet = ngModelGet.assign;

                  buttonsCtrl.addButton(scope, ngModelSet);

                  //ui->model
                  element.bind('click', function() {
                    scope.$apply(function() {
                      ngModelCtrl.$setViewValue(!ngModelCtrl.$viewValue);
                      ngModelCtrl.$render();
                    });
                  });

                  //model -> UI
                  ngModelCtrl.$render = function() {
                    if (ngModelCtrl.$viewValue) {
                      buttonsCtrl.activate(scope);
                    }
                    element.toggleClass('active', ngModelCtrl.$viewValue);
                  };
                }
          };
        }]);
})();
<|endoftext|>


<commit_before>import Vue from 'vue/dist/vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const Home = { template: '
home
' }
const Foo = { template: '
foo
' }
const Bar = {
  template: `

      bar

Anchor

  `
}

// scrollBehavior:
// - only available in html5 history mode
// - defaults to no scroll behavior
// - return false to prevent scroll
const scrollBehavior = (to, from, savedPosition) => {
  if (savedPosition) {
    // savedPosition is only available for popstate navigations.
    return savedPosition
  } else {
    let position = {}
    // new navigation.
    // scroll to anchor by returning the selector
    if (to.hash) {
      position.selector = to.hash
    }
    // check if any matched route config has meta that requires scrolling to top
    if (to.matched.some(m => m.meta.scrollToTop)) {
      // cords will be used if no selector is provided,
      // or if the selector didn't match any element.
      position.x = 0
      position.y = 0
    }
    // if the returned position is falsy or an empty object,
    // will retain current scroll position.
    return position
  }
}

const router = new VueRouter({
  mode: 'history',
  base: __dirname,
  scrollBehavior,
  routes: [
    { path: '/', component: Home, meta: { scrollToTop: true }},
    { path: '/foo', component: Foo },
    { path: '/bar', component: Bar, meta: { scrollToTop: true }}
  ]
})

new Vue({
  router,
  template: `

Scroll Behavior

<router-link to="/">/</router-link>

<router-link to="/foo">/foo</router-link>

<router-link to="/bar">/bar</router-link>

<router-link to="/bar#anchor">/bar#anchor</router-link>

      <router-view class="view"></router-view>

  `
}).$mount('#app')
<commit_msg>fix lint<commit_after>import Vue from 'vue/dist/vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const Home = { template: '
home
' }
const Foo = { template: '
foo
' }
const Bar = {
  template: `

      bar

Anchor

  `
}

// scrollBehavior:
// - only available in html5 history mode
// - defaults to no scroll behavior
// - return false to prevent scroll
const scrollBehavior = (to, from, savedPosition) => {
  if (savedPosition) {
    // savedPosition is only available for popstate navigations.
    return savedPosition
  } else {
    const position = {}
    // new navigation.
    // scroll to anchor by returning the selector
    if (to.hash) {
      position.selector = to.hash
    }
    // check if any matched route config has meta that requires scrolling to top
    if (to.matched.some(m => m.meta.scrollToTop)) {
      // cords will be used if no selector is provided,
      // or if the selector didn't match any element.
      position.x = 0
      position.y = 0
    }
    // if the returned position is falsy or an empty object,
    // will retain current scroll position.
    return position
  }
}

const router = new VueRouter({
  mode: 'history',
  base: __dirname,
  scrollBehavior,
  routes: [
    { path: '/', component: Home, meta: { scrollToTop: true }},
    { path: '/foo', component: Foo },
    { path: '/bar', component: Bar, meta: { scrollToTop: true }}
  ]
})

new Vue({
  router,
  template: `

Scroll Behavior

<router-link to="/">/</router-link>

<router-link to="/foo">/foo</router-link>

<router-link to="/bar">/bar</router-link>

<router-link to="/bar#anchor">/bar#anchor</router-link>

      <router-view class="view"></router-view>

  `
}).$mount('#app')
<|endoftext|>


<commit_before>'use strict';

define(['angular', 'ol', 'toolbar', 'layermanager', 'SparqlJson', 'WfsSource', 'core', 'map', 'query', 'search', 'print', 'permalink', 'measure', 'geolocation', 'angular-gettext','translations'],

    function(angular, ol, toolbar, layermanager, SparqlJson, WfsSource) {
        var module = angular.module('hs', [
            'hs.core',
            'hs.toolbar',
            'hs.layermanager',
            'hs.map',
            'hs.query',
            'hs.search', 'hs.print', 'hs.permalink',
            'hs.geolocation',
            'gettext'
        ]);

        module.directive('hs', ['OlMap', 'Core', function(OlMap, Core) {
            return {
                templateUrl: hsl_path + 'hslayers.html',
                link: function(scope, element) {
                    Core.fullscreenMap(element);
                }
            };
        }]);

        module.service('feature_crossfilter',[function(){
            return {
                makeCrossfilterDimensions : function(source, attribute){
                    var total = source.getFeatures().dimension( function(source) {
                        //return
                    });
                    var groupsByTotal = total.group( function(source) {
                        return source.get(attribute);
                    });
                    console.log('test');
                    // caur konsoli: var a = angular.element('*[ng-app]').injector().get('hsService');
                }
            };
        }]);

        module.value('box_layers', []);

        var style = new ol.style.Style({
            image: new ol.style.Circle({
                fill: new ol.style.Fill({
                    color: [242, 121, 0, 0.7]
                }),
                stroke: new ol.style.Stroke({
                    color: [0xbb, 0x33, 0x33, 0.7]
                }),
                radius: 5
            }),
            fill: new ol.style.Fill({
                color: "rgba(139, 189, 214, 0.3)",
            }),
            stroke: new ol.style.Stroke({
                color: '#112211',
                width: 1
            })
        });

        var style_sparql = function(feature, resolution) {
            return [new ol.style.Style({
                image: new ol.style.Circle({
                    fill: new ol.style.Fill({
                        color: feature.color ? feature.color : [242, 121, 0, 0.7]
                    }),
                    stroke: new ol.style.Stroke({
                        color: [0x33, 0x33, 0x33, 0.9]
                    }),
                    radius: 5
                }),
                fill: new ol.style.Fill({
                    color: "rgba(139, 189, 214, 0.3)",
                }),
                stroke: new ol.style.Stroke({
                    color: '#112211',
                    width: 1
                })
            })]
        }

        module.value('default_layers', [
            new ol.layer.Tile({
                source: new ol.source.OSM(),
                title: "Base layer",
                box_id: 'osm',
                base: true
            }),
            new ol.layer.Vector({
                title: "Accidents",
                source: new WfsSource({
                    url: 'http://otn.bnhelp.cz/cgi-bin/mapserv?map=/data/www/otn.bnhelp.cz/maps/accidents_west_midlands.map',
                    typename: 'wm_accidents',
                    projection: 'EPSG:3857'
                }),
                style: style
            }),
            new ol.layer.Vector({
                title: "Points of interest",
                source: new SparqlJson({
                    url: 'http://ha.isaf2014.info:8890/sparql?default-graph-uri=&query=SELECT+*+FROM+%3Chttp%3A%2F%2Fgis.zcu.cz%2Fpoi.rdf%3E+WHERE+%7B%3Fo+%3Fp+%3Fs%7D%0D%0AORDER+BY+%3Fo&should-sponge=&format=application%2Fsparql-results%2Bjson&timeout=0&debug=on',
                    category_field: 'http://gis.zcu.cz/poi#category',
                    projection: 'EPSG:3857'
                }),
                style: style_sparql
            })
        ]);

        module.value('default_view', new ol.View({
            center: ol.proj.transform([17.474129, 52.574000], 'EPSG:4326', 'EPSG:3857'), //Latitude longitude    to Spherical Mercator
            zoom: 4,
            units: "m"
        }));

        module.controller('Main', ['$scope', 'Core', 'InfoPanelService', 'OlMap', 'feature_crossfilter',
            function($scope, Core, InfoPanelService, OlMap, feature_crossfilter) {
                if (console) console.log("Main called");
                $scope.hsl_path = hsl_path; //Get this from hslayers.js file
                $scope.Core = Core;
                setTimeout(function(){
                    debugger;
                    feature_crossfilter.makeCrossfilterDimensions(OlMap.map.getLayers().item(1).getSource(), ["someattr"]);
                }, 4000);
                $scope.$on('infopanel.updated', function(event) {});
            }
        ]);

        return module;
    });
<commit_msg>category attribute in wfscrossfilter example<commit_after>'use strict';

define(['angular', 'ol', 'toolbar', 'layermanager', 'SparqlJson', 'WfsSource', 'core', 'map', 'query', 'search', 'print', 'permalink', 'measure', 'geolocation', 'angular-gettext','translations'],

    function(angular, ol, toolbar, layermanager, SparqlJson, WfsSource) {
        var module = angular.module('hs', [
            'hs.core',
            'hs.toolbar',
            'hs.layermanager',
            'hs.map',
            'hs.query',
            'hs.search', 'hs.print', 'hs.permalink',
            'hs.geolocation',
            'gettext'
        ]);

        module.directive('hs', ['OlMap', 'Core', function(OlMap, Core) {
            return {
                templateUrl: hsl_path + 'hslayers.html',
                link: function(scope, element) {
                    Core.fullscreenMap(element);
                }
            };
        }]);

        module.service('feature_crossfilter',[function(){
            return {
                makeCrossfilterDimensions : function(source, attribute){
                    var total = source.getFeatures().dimension( function(source) {
                        //return
                    });
                    var groupsByTotal = total.group( function(source) {
                        return source.get(attribute);
                    });
                    console.log('test');
                    // caur konsoli: var a = angular.element('*[ng-app]').injector().get('hsService');
                }
            };
        }]);

        module.value('box_layers', []);

        var style = new ol.style.Style({
            image: new ol.style.Circle({
                fill: new ol.style.Fill({
                    color: [242, 121, 0, 0.7]
                }),
                stroke: new ol.style.Stroke({
                    color: [0xbb, 0x33, 0x33, 0.7]
                }),
                radius: 5
            }),
            fill: new ol.style.Fill({
                color: "rgba(139, 189, 214, 0.3)",
            }),
            stroke: new ol.style.Stroke({
                color: '#112211',
                width: 1
            })
        });

        var style_sparql = function(feature, resolution) {
            return [new ol.style.Style({
                image: new ol.style.Circle({
                    fill: new ol.style.Fill({
                        color: feature.color ? feature.color : [242, 121, 0, 0.7]
                    }),
                    stroke: new ol.style.Stroke({
                        color: [0x33, 0x33, 0x33, 0.9]
                    }),
                    radius: 5
                }),
                fill: new ol.style.Fill({
                    color: "rgba(139, 189, 214, 0.3)",
                }),
                stroke: new ol.style.Stroke({
                    color: '#112211',
                    width: 1
                })
            })]
        }

        module.value('default_layers', [
            new ol.layer.Tile({
                source: new ol.source.OSM(),
                title: "Base layer",
                box_id: 'osm',
                base: true
            }),
            new ol.layer.Vector({
                title: "Accidents",
                source: new WfsSource({
                    url: 'http://otn.bnhelp.cz/cgi-bin/mapserv?map=/data/www/otn.bnhelp.cz/maps/accidents_west_midlands.map',
                    typename: 'wm_accidents',
                    projection: 'EPSG:3857'
                }),
                style: style
            }),
            new ol.layer.Vector({
                title: "Points of interest",
                source: new SparqlJson({
                    url: 'http://ha.isaf2014.info:8890/sparql?default-graph-uri=&query=SELECT+*+FROM+%3Chttp%3A%2F%2Fgis.zcu.cz%2Fpoi.rdf%3E+WHERE+%7B%3Fo+%3Fp+%3Fs%7D%0D%0AORDER+BY+%3Fo&should-sponge=&format=application%2Fsparql-results%2Bjson&timeout=0&debug=on',
                    category_field: 'http://gis.zcu.cz/poi#category',
                    projection: 'EPSG:3857'
                }),
                style: style_sparql
            })
        ]);

        module.value('default_view', new ol.View({
            center: ol.proj.transform([17.474129, 52.574000], 'EPSG:4326', 'EPSG:3857'), //Latitude longitude    to Spherical Mercator
            zoom: 4,
            units: "m"
        }));

        module.controller('Main', ['$scope', 'Core', 'InfoPanelService', 'OlMap', 'feature_crossfilter',
            function($scope, Core, InfoPanelService, OlMap, feature_crossfilter) {
                if (console) console.log("Main called");
                $scope.hsl_path = hsl_path; //Get this from hslayers.js file
                $scope.Core = Core;
                setTimeout(function(){
                    feature_crossfilter.makeCrossfilterDimensions(OlMap.map.getLayers().item(1).getSource(), ["http://gis.zcu.cz/poi#category_os"]);
                }, 4000);
                $scope.$on('infopanel.updated', function(event) {});
            }
        ]);

        return module;
    });
<|endoftext|>


<commit_before>// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
  "use strict";

  var tables;
  var defaultTable;
  var keywords;
  var CONS = {
    QUERY_DIV: ";",
    ALIAS_KEYWORD: "AS"
  };
  var Pos = CodeMirror.Pos;

  function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" }

  function getKeywords(editor) {
    var mode = editor.doc.modeOption;
    if (mode === "sql") mode = "text/x-sql";
    return CodeMirror.resolveMode(mode).keywords;
  }

  function getText(item) {
    return typeof item == "string" ? item : item.text;
  }

  function wrapTable(name, value) {
    if (isArray(value)) value = {columns: value}
    if (!value.text) value.text = name
    return value
  }

  function parseTables(input) {
    var result = {}
    if (isArray(input)) {
      for (var i = input.length - 1; i >= 0; i--) {
        var item = input[i]
        result[getText(item).toUpperCase()] = wrapTable(getText(item), item)
      }
    } else if (input) {
      for (var name in input)
        result[name.toUpperCase()] = wrapTable(name, input[name])
    }
    return result
  }

  function getTable(name) {
    return tables[name.toUpperCase()]
  }

  function shallowClone(object) {
    var result = {};
    for (var key in object) if (object.hasOwnProperty(key))
      result[key] = object[key];
    return result;
  }

  function match(string, word) {
    var len = string.length;
    var sub = getText(word).substr(0, len);
    return string.toUpperCase() === sub.toUpperCase();
  }

  function addMatches(result, search, wordlist, formatter) {
    if (isArray(wordlist)) {
      for (var i = 0; i < wordlist.length; i++)
        if (match(search, wordlist[i])) result.push(formatter(wordlist[i]))
    } else {
      for (var word in wordlist) if (wordlist.hasOwnProperty(word)) {
        var val = wordlist[word]
        if (!val || val === true)
          val = word
        else
          val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text
        if (match(search, val)) result.push(formatter(val))
      }
    }
  }

  function cleanName(name) {
    // Get rid name from backticks(`) and preceding dot(.)
    if (name.charAt(0) == ".") {
      name = name.substr(1);
    }
    return name.replace(/`/g, "");
  }

  function insertBackticks(name) {
    var nameParts = getText(name).split(".");
    for (var i = 0; i < nameParts.length; i++)
      nameParts[i] = "`" + nameParts[i] + "`";
    var escaped = nameParts.join(".");
    if (typeof name == "string") return escaped;
    name = shallowClone(name);
    name.text = escaped;
    return name;
  }

  function nameCompletion(cur, token, result, editor) {
    // Try to complete table, column names and return start position of completion
    var useBacktick = false;
    var nameParts = [];
    var start = token.start;
    var cont = true;
    while (cont) {
      cont = (token.string.charAt(0) == ".");
      useBacktick = useBacktick || (token.string.charAt(0) == "`");

      start = token.start;
      nameParts.unshift(cleanName(token.string));

      token = editor.getTokenAt(Pos(cur.line, token.start));
      if (token.string == ".") {
        cont = true;
        token = editor.getTokenAt(Pos(cur.line, token.start));
      }
    }

    // Try to complete table names
    var string = nameParts.join(".");
    addMatches(result, string, tables, function(w) {
      return useBacktick ? insertBackticks(w) : w;
    });

    // Try to complete columns from defaultTable
    addMatches(result, string, defaultTable, function(w) {
      return useBacktick ? insertBackticks(w) : w;
    });

    // Try to complete columns
    string = nameParts.pop();
    var table = nameParts.join(".");

    var alias = false;
    var aliasTable = table;
    // Check if table is available. If not, find table by Alias
    if (!getTable(table)) {
      var oldTable = table;
      table = findTableByAlias(table, editor);
      if (table !== oldTable) alias = true;
    }

    var columns = getTable(table);
    if (columns && columns.columns)
      columns = columns.columns;

    if (columns) {
      addMatches(result, string, columns, function(w) {
        var tableInsert = table;
        if (alias == true) tableInsert = aliasTable;
        if (typeof w == "string") {
          w = tableInsert + "." + w;
        } else {
          w = shallowClone(w);
          w.text = tableInsert + "." + w.text;
        }
        return useBacktick ? insertBackticks(w) : w;
      });
    }

    return start;
  }

  function eachWord(lineText, f) {
    if (!lineText) return;
    var excepted = /[,;]/g;
    var words = lineText.split(" ");
    for (var i = 0; i < words.length; i++) {
      f(words[i]?words[i].replace(excepted, '') : '');
    }
  }

  function convertCurToNumber(cur) {
    // max characters of a line is 999,999.
    return cur.line + cur.ch / Math.pow(10, 6);
  }

  function convertNumberToCur(num) {
    return Pos(Math.floor(num), +num.toFixed(6).toString().split('.').pop());
  }

  function findTableByAlias(alias, editor) {
    var doc = editor.doc;
    var fullQuery = doc.getValue();
    var aliasUpperCase = alias.toUpperCase();
    var previousWord = "";
    var table = "";
    var separator = [];
    var validRange = {
      start: Pos(0, 0),
      end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length)
    };

    //add separator
    var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV);
    while(indexOfSeparator != -1) {
      separator.push(doc.posFromIndex(indexOfSeparator));
      indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1);
    }
    separator.unshift(Pos(0, 0));
    separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));

    //find valid range
    var prevItem = 0;
    var current = convertCurToNumber(editor.getCursor());
    for (var i = 0; i < separator.length; i++) {
      var _v = convertCurToNumber(separator[i]);
      if (current > prevItem && current <= _v) {
        validRange = { start: convertNumberToCur(prevItem), end: convertNumberToCur(_v) };
        break;
      }
      prevItem = _v;
    }

    var query = doc.getRange(validRange.start, validRange.end, false);

    for (var i = 0; i < query.length; i++) {
      var lineText = query[i];
      eachWord(lineText, function(word) {
        var wordUpperCase = word.toUpperCase();
        if (wordUpperCase === aliasUpperCase && getTable(previousWord))
          table = previousWord;
        if (wordUpperCase !== CONS.ALIAS_KEYWORD)
          previousWord = word;
      });
      if (table) break;
    }
    return table;
  }

  CodeMirror.registerHelper("hint", "sql", function(editor, options) {
    tables = parseTables(options && options.tables)
    var defaultTableName = options && options.defaultTable;
    var disableKeywords = options && options.disableKeywords;
    defaultTable = defaultTableName && getTable(defaultTableName);
    keywords = getKeywords(editor);

    if (defaultTableName && !defaultTable)
      defaultTable = findTableByAlias(defaultTableName, editor);

    defaultTable = defaultTable || [];

    if (defaultTable.columns)
      defaultTable = defaultTable.columns;

    var cur = editor.getCursor();
    var result = [];
    var token = editor.getTokenAt(cur), start, end, search;
    if (token.end > cur.ch) {
      token.end = cur.ch;
      token.string = token.string.slice(0, cur.ch - token.start);
    }

    if (token.string.match(/^[.`\w@]\w*$/)) {
      search = token.string;
      start = token.start;
      end = token.end;
    } else {
      start = end = cur.ch;
      search = "";
    }
    if (search.charAt(0) == "." || search.charAt(0) == "`") {
      start = nameCompletion(cur, token, result, editor);
    } else {
      addMatches(result, search, tables, function(w) {return w;});
      addMatches(result, search, defaultTable, function(w) {return w;});
      if (!disableKeywords)
        addMatches(result, search, keywords, function(w) {return w.toUpperCase();});
    }

    return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};
  });
});
<commit_msg>[sql-hint addon] Remove strange hack<commit_after>// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function(mod) {
  if (typeof exports == "object" && typeof module == "object") // CommonJS
    mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
  else if (typeof define == "function" && define.amd) // AMD
    define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
  else // Plain browser env
    mod(CodeMirror);
})(function(CodeMirror) {
  "use strict";

  var tables;
  var defaultTable;
  var keywords;
  var CONS = {
    QUERY_DIV: ";",
    ALIAS_KEYWORD: "AS"
  };
  var Pos = CodeMirror.Pos, cmpPos = CodeMirror.cmpPos;

  function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" }

  function getKeywords(editor) {
    var mode = editor.doc.modeOption;
    if (mode === "sql") mode = "text/x-sql";
    return CodeMirror.resolveMode(mode).keywords;
  }

  function getText(item) {
    return typeof item == "string" ? item : item.text;
  }

  function wrapTable(name, value) {
    if (isArray(value)) value = {columns: value}
    if (!value.text) value.text = name
    return value
  }

  function parseTables(input) {
    var result = {}
    if (isArray(input)) {
      for (var i = input.length - 1; i >= 0; i--) {
        var item = input[i]
        result[getText(item).toUpperCase()] = wrapTable(getText(item), item)
      }
    } else if (input) {
      for (var name in input)
        result[name.toUpperCase()] = wrapTable(name, input[name])
    }
    return result
  }

  function getTable(name) {
    return tables[name.toUpperCase()]
  }

  function shallowClone(object) {
    var result = {};
    for (var key in object) if (object.hasOwnProperty(key))
      result[key] = object[key];
    return result;
  }

  function match(string, word) {
    var len = string.length;
    var sub = getText(word).substr(0, len);
    return string.toUpperCase() === sub.toUpperCase();
  }

  function addMatches(result, search, wordlist, formatter) {
    if (isArray(wordlist)) {
      for (var i = 0; i < wordlist.length; i++)
        if (match(search, wordlist[i])) result.push(formatter(wordlist[i]))
    } else {
      for (var word in wordlist) if (wordlist.hasOwnProperty(word)) {
        var val = wordlist[word]
        if (!val || val === true)
          val = word
        else
          val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text
        if (match(search, val)) result.push(formatter(val))
      }
    }
  }

  function cleanName(name) {
    // Get rid name from backticks(`) and preceding dot(.)
    if (name.charAt(0) == ".") {
      name = name.substr(1);
    }
    return name.replace(/`/g, "");
  }

  function insertBackticks(name) {
    var nameParts = getText(name).split(".");
    for (var i = 0; i < nameParts.length; i++)
      nameParts[i] = "`" + nameParts[i] + "`";
    var escaped = nameParts.join(".");
    if (typeof name == "string") return escaped;
    name = shallowClone(name);
    name.text = escaped;
    return name;
  }

  function nameCompletion(cur, token, result, editor) {
    // Try to complete table, column names and return start position of completion
    var useBacktick = false;
    var nameParts = [];
    var start = token.start;
    var cont = true;
    while (cont) {
      cont = (token.string.charAt(0) == ".");
      useBacktick = useBacktick || (token.string.charAt(0) == "`");

      start = token.start;
      nameParts.unshift(cleanName(token.string));

      token = editor.getTokenAt(Pos(cur.line, token.start));
      if (token.string == ".") {
        cont = true;
        token = editor.getTokenAt(Pos(cur.line, token.start));
      }
    }

    // Try to complete table names
    var string = nameParts.join(".");
    addMatches(result, string, tables, function(w) {
      return useBacktick ? insertBackticks(w) : w;
    });

    // Try to complete columns from defaultTable
    addMatches(result, string, defaultTable, function(w) {
      return useBacktick ? insertBackticks(w) : w;
    });

    // Try to complete columns
    string = nameParts.pop();
    var table = nameParts.join(".");

    var alias = false;
    var aliasTable = table;
    // Check if table is available. If not, find table by Alias
    if (!getTable(table)) {
      var oldTable = table;
      table = findTableByAlias(table, editor);
      if (table !== oldTable) alias = true;
    }

    var columns = getTable(table);
    if (columns && columns.columns)
      columns = columns.columns;

    if (columns) {
      addMatches(result, string, columns, function(w) {
        var tableInsert = table;
        if (alias == true) tableInsert = aliasTable;
        if (typeof w == "string") {
          w = tableInsert + "." + w;
        } else {
          w = shallowClone(w);
          w.text = tableInsert + "." + w.text;
        }
        return useBacktick ? insertBackticks(w) : w;
      });
    }

    return start;
  }

  function eachWord(lineText, f) {
    if (!lineText) return;
    var excepted = /[,;]/g;
    var words = lineText.split(" ");
    for (var i = 0; i < words.length; i++) {
      f(words[i]?words[i].replace(excepted, '') : '');
    }
  }

  function findTableByAlias(alias, editor) {
    var doc = editor.doc;
    var fullQuery = doc.getValue();
    var aliasUpperCase = alias.toUpperCase();
    var previousWord = "";
    var table = "";
    var separator = [];
    var validRange = {
      start: Pos(0, 0),
      end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length)
    };

    //add separator
    var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV);
    while(indexOfSeparator != -1) {
      separator.push(doc.posFromIndex(indexOfSeparator));
      indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1);
    }
    separator.unshift(Pos(0, 0));
    separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));

    //find valid range
    var prevItem = null;
    var current = editor.getCursor()
    for (var i = 0; i < separator.length; i++) {
      if ((prevItem == null || cmpPos(current, prevItem) > 0) && cmpPos(current, separator[i]) <= 0) {
        validRange = {start: prevItem, end: separator[i]};
        break;
      }
      prevItem = separator[i];
    }

    var query = doc.getRange(validRange.start, validRange.end, false);

    for (var i = 0; i < query.length; i++) {
      var lineText = query[i];
      eachWord(lineText, function(word) {
        var wordUpperCase = word.toUpperCase();
        if (wordUpperCase === aliasUpperCase && getTable(previousWord))
          table = previousWord;
        if (wordUpperCase !== CONS.ALIAS_KEYWORD)
          previousWord = word;
      });
      if (table) break;
    }
    return table;
  }

  CodeMirror.registerHelper("hint", "sql", function(editor, options) {
    tables = parseTables(options && options.tables)
    var defaultTableName = options && options.defaultTable;
    var disableKeywords = options && options.disableKeywords;
    defaultTable = defaultTableName && getTable(defaultTableName);
    keywords = getKeywords(editor);

    if (defaultTableName && !defaultTable)
      defaultTable = findTableByAlias(defaultTableName, editor);

    defaultTable = defaultTable || [];

    if (defaultTable.columns)
      defaultTable = defaultTable.columns;

    var cur = editor.getCursor();
    var result = [];
    var token = editor.getTokenAt(cur), start, end, search;
    if (token.end > cur.ch) {
      token.end = cur.ch;
      token.string = token.string.slice(0, cur.ch - token.start);
    }

    if (token.string.match(/^[.`\w@]\w*$/)) {
      search = token.string;
      start = token.start;
      end = token.end;
    } else {
      start = end = cur.ch;
      search = "";
    }
    if (search.charAt(0) == "." || search.charAt(0) == "`") {
      start = nameCompletion(cur, token, result, editor);
    } else {
      addMatches(result, search, tables, function(w) {return w;});
      addMatches(result, search, defaultTable, function(w) {return w;});
      if (!disableKeywords)
        addMatches(result, search, keywords, function(w) {return w.toUpperCase();});
    }

    return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};
  });
});
<|endoftext|>


<commit_before>//(c) 2014 Indexia, Inc.
import Em from 'ember';

/**
 * A confirmation modal with 'Yes' & 'No' buttons
 * When 'no' is pressed the modal is just closed.
 * When 'yes' is pressed an action bound to the action on the controller set in the `confirm` property is invoked,
 * giving the controller a chance to decide whether to close the modal or not.
 *
 * @class ModalConfirm
 */
export default Em.Component.extend({
  /**
   * Bound to the action on the controller to be invoked when the 'yes' button is pressed.
   * @property confirm
   * @public
   */
  confirm: "confirm",

  /**
   * The default title of the modal if not set otherwise.
   *
   * @property title
   * @public
   */
  title: 'Please confirm',

  /**
   * The default message of the modal if not set otherwise.
   *
   * @property message
   * @public
   */
  message: 'Please press Yes to confirm the operation.',
  'modal-title-classes': '',
  'cancel-button-title': 'No',
  'cancel-button-icons': 'fa fa-thumbs-o-down',
  'cancel-button-classes': 'btn btn-primary',
  'submit-button-classes': 'btn btn-default',
  'submit-button-title': 'Yes',
  'submit-button-submitting-title': 'Submitting...',
  'submit-button-default-icons': 'fa fa-thumbs-o-up',
  'submit-button-execute-icons': 'fa fa-spinner fa-spin',
  actions: {

    /**
     * Invoked when the user clicks the "Yes" button, triggers an action on the controller.
     *
     * @method confirmPressed
     * @private
     */
    confirmPressed: function(setPromise) {
      return this.sendAction('confirm', setPromise);
    }
  }
});
<commit_msg>Change css classes<commit_after>//(c) 2014 Indexia, Inc.
import Em from 'ember';

/**
 * A confirmation modal with 'Yes' & 'No' buttons
 * When 'no' is pressed the modal is just closed.
 * When 'yes' is pressed an action bound to the action on the controller set in the `confirm` property is invoked,
 * giving the controller a chance to decide whether to close the modal or not.
 *
 * @class ModalConfirm
 */
export default Em.Component.extend({
  /**
   * Bound to the action on the controller to be invoked when the 'yes' button is pressed.
   * @property confirm
   * @public
   */
  confirm: "confirm",

  /**
   * The default title of the modal if not set otherwise.
   *
   * @property title
   * @public
   */
  title: 'Please confirm',

  /**
   * The default message of the modal if not set otherwise.
   *
   * @property message
   * @public
   */
  message: 'Please press Yes to confirm the operation.',
  'modal-title-classes': '',
  'cancel-button-title': 'No',
  'cancel-button-icons': 'fa fa-thumbs-o-down',
  'cancel-button-classes': 'btn btn-default',
  'submit-button-classes': 'btn btn-primary',
  'submit-button-title': 'Yes',
  'submit-button-submitting-title': 'Submitting...',
  'submit-button-default-icons': 'fa fa-thumbs-o-up',
  'submit-button-execute-icons': 'fa fa-spinner fa-spin',
  actions: {

    /**
     * Invoked when the user clicks the "Yes" button, triggers an action on the controller.
     *
     * @method confirmPressed
     * @private
     */
    confirmPressed: function(setPromise) {
      return this.sendAction('confirm', setPromise);
    }
  }
});
<|endoftext|>


<commit_before>'use strict'

const jsonfile = require('jsonfile')
const path = require('path')
const version = require('../package.json').version

// Some default values for app/package.json
let jsonObj = {
  'name': 'Soundwave nteractive',
  'productName': 'Soundwave Interactive',
  'version': version,
  'description': 'Soundwave Interactive Soundboard',
  'author': 'Derek Jensen <derek@deek.io>',
  'private': false,
  'license': 'MIT',
  'homepage': 'github.com/DeekyJay',
  'main': './main.js',
  'dependencies': {}
}

const devPackage = path.resolve(process.cwd(), 'package.json')
const appPackage = path.resolve(process.cwd(), 'app/package.json')

jsonfile.readFile(devPackage, (err, obj) => {
  if (err) {
    throw new Error(err)
  } else {
    jsonObj.dependencies = obj.dependencies
    jsonfile.writeFile(appPackage, jsonObj, (err) => {
      if (err) {
        throw new Error(err)
      }
    })
  }
})
<commit_msg>Fixed Broken Name<commit_after>'use strict'

const jsonfile = require('jsonfile')
const path = require('path')
const version = require('../package.json').version

// Some default values for app/package.json
let jsonObj = {
  'name': 'SoundwaveInteractive',
  'productName': 'Soundwave Interactive',
  'version': version,
  'description': 'Soundwave Interactive Soundboard',
  'author': 'Derek Jensen <derek@deek.io>',
  'private': false,
  'license': 'MIT',
  'homepage': 'github.com/DeekyJay',
  'main': './main.js',
  'dependencies': {}
}

const devPackage = path.resolve(process.cwd(), 'package.json')
const appPackage = path.resolve(process.cwd(), 'app/package.json')

jsonfile.readFile(devPackage, (err, obj) => {
  if (err) {
    throw new Error(err)
  } else {
    jsonObj.dependencies = obj.dependencies
    jsonfile.writeFile(appPackage, jsonObj, (err) => {
      if (err) {
        throw new Error(err)
      }
    })
  }
})
<|endoftext|>


<commit_before>import { isBlank } from '@ember/utils';
import { assert } from '@ember/debug';
import {
  resolve,
  reject,
  hash
} from 'rsvp';
import { computed } from '@ember/object';
import Service from '@ember/service';
import i18next from 'i18next';
import i18nextXHRBackend from 'i18next-xhr-backend';

import config from 'ember-i18next/configuration';

/**
 * A service that exposes functionality from i18next.
 */
const I18nService = Service.extend({
  i18next: null,
  isInitialized: false,

  _locale: null,
  _preInitActions: null,
  _postInitActions: null,

  _errors: null,

  init() {
    this._super(...arguments);
    this.set('i18next', i18next);
    this.set('_preInitActions', {});
    this.set('_postInitActions', {});
  },

  /**
   * The current locale. This is a settable computed property; when set, the locale
   * will be changed using `i18next.setLng()` and registered pre- and post-init
   * actions will run. Finally, the locale will change, triggering a refresh of
   * localized text.
   */
  locale: computed('i18next', '_locale', {
    get() {
      return this.get('_locale');
    },
    set(key, value) {
      const lang = value;

      if (this.get('isInitialized')) {
        this._changeLocale(lang)
          .then(lang => this.set('_locale', lang));
      } else {
        this.set('_locale', lang);
      }

      return lang;
    }
  }),

  /**
   * Initializes the i18next library with configuration from the environment.
   *
   * @return {Promise} - a promise that resolves with the i18next object when
   *   i18next has finished initializing.
   */
  initLibraryAsync() {
    const i18next = this.get('i18next');

    return this._runPreInitActions()
      .then(() => this._initLibrary())
      .then(() => this._runPostInitActions())
      .then(() => {
        this.set('_locale', i18next.language);
        this.set('isInitialized', true);
        return resolve();
      }).catch(reason => {
        // eslint-disable-next-line no-console
        console.warn(`A promise in the i18next init chain rejected with reason: ${reason}`);
        return reject(reason);
      });
  },

  /**
   * Registers an action to execute before initializing i18next. Before initializing
   * the library or setting the language (which reinitializes the library), each of
   * the registered actions will be executed.
   *
   * If any pre-init actions return a promise, the service will wait until all the
   * promises have settled before initializing i18next.
   *
   * @param {String|Object} key -  the key to use to look up the action. May not be
   *   blank.
   * @param {Function} fn - a zero-argument callback function. Return a promise if
   *   the operation needs to complete before the i18next is initialized.
   */
  registerPreInitAction(key, fn) {
    assert('Pre-init action key may not be blank', !isBlank(key));
    assert('A pre-init action must be a function', typeof fn === 'function');
    this.get('_preInitActions')[key] = fn;
  },

  /**
   * Removes an action from the set of actions executed before initializing i18next.
   *
   * @param {String|Object} key - the key to use to look up the action to remove.
   *   May not be blank.
   */
  unregisterPreInitAction(key) {
    assert('Action key may not be blank', !isBlank(key));
    const preInitActions = this.get('_preInitActions');

    delete preInitActions[key];
  },

  /**
   * Registers an action to execute after initializing i18next. After initializing
   * the library or setting the language (which reinitializes the library), each of
   * the registered actions will be executed.
   *
   * If any post-init actions return a promise, the service will wait until all the
   * promises have settled before triggering a UI refresh.
   *
   * @param {String|Object} key -  the key to use to look up the action. May not be
   *   blank.
   * @param {Function} fn - a zero-argument callback function. Return a promise if
   *   the operation needs to complete before the the UI is refreshed.
   */
  registerPostInitAction(name, fn) {
    assert('Pre-init action name may not be blank', !isBlank(name));
    assert('A post-init action must be a function', typeof fn === 'function');
    this.get('_postInitActions')[name] = fn;
  },

  /**
   * Removes an action from the set of actions executed after initializing i18next.
   *
   * @param {String|Object} key - the key to use to look up the action to remove.
   *   May not be blank.
   */
  unregisterPostInitAction(key) {
    assert('Action key may not be blank', !isBlank(key));
    const postInitActions = this.get('_postInitActions');

    delete postInitActions[key];
  },

  /**
   * Changes the locale, ensuring that pre- and post-init actions run.
   *
   * @param {String} lang - locale code to set.
   *
   * @return {Promise} a promise that resolves with the language code when complete.
   */
  _changeLocale(lang) {
    const i18next = this.get('i18next');

    if (i18next && lang && i18next.language === lang) {
      return resolve(lang);
    }

    const oldLang = this._locale;
    return this._runPreInitActions(lang)
      .then(() => this._setLng(lang))
      .then(() => this._runPostInitActions(oldLang))
      .then(() => resolve(lang))
      .catch(reason => {
        // eslint-disable-next-line no-console
        console.warn(`A promise in the locale change path rejected with reason: ${reason}`);
      });
  },

  /**
   * Forwarded to `i18next.t()`.
   *
   * @param {String} path - an string that specifies the translation lookup key.
   *   Required.
   * @param {Object} values - an object that specifies values to substitute into
   *   the translation for the specified path. Optional.
   *
   * @return Localized text.
   */
  t(path, values) {
    const i18next = this.get('i18next');
    return i18next.t(path, values);
  },

  /**
   * Forwarded to `i18next.addResourceBundle()`.
   */
  addResourceBundle(lang, ns, resources, deep, overwrite) {
    return this.get('i18next').addResourceBundle(lang, ns, resources, deep, overwrite);
  },

  /**
   * Forwarded to `i18next.hasResourceBundle()`.
   */
  hasResourceBundle(lang, ns) {
    return this.get('i18next').hasResourceBundle(lang, ns);
  },

  /**
   * Forwarded to `i18next.getResourceBundle()`.
   */
  getResourceBundle(lang, ns) {
    return this.get('i18next').getResourceBundle(lang, ns);
  },

  /**
   * Forwarded to `i18next.removeResourceBundle()`.
   */
  removeResourceBundle(lang, ns) {
    return this.get('i18next').removeResourceBundle(lang, ns);
  },

  /**
   * Forwarded to `i18next.addResource()`.
   */
  addResource(lang, ns, key, value, options) {
    return this.get('i18next').addResource(lang, ns, key, value, options);
  },

  /**
   * Forwarded to `i18next.addResources()`.
   */
  addResources(lang, ns, resources) {
    return this.get('i18next').addResources(lang, ns, resources);
  },

  /**
   * Forwarded to `i18next.loadNamespaces()`.
   */
  loadNamespaces(namespaces, callback) {
    return this.get('i18next').loadNamespaces(namespaces, callback);
  },

  /**
   * Forwarded to `i18next.setDefaultNamespace()`.
   */
  setDefaultNamespace(ns) {
    return this.get('i18next').setDefaultNamespace(ns);
  },

  /**
   * Alias for `t()`.
   */
  translate(key, values) {
    return this.t(key, values);
  },

  /**
   * Forwarded to `i18next.exists()`.
   */
  exists(key, options) {
    return this.get('i18next').exists(key, options);
  },

  /**
   * Gets i18next's `pluralExtensions` property.
   */
  pluralExtensions: computed('i18next', function () {
    return this.get('i18next').pluralExtensions;
  }),

  /**
   * Forwarded to `i18next.addPostProcessor()`.
   */
  addPostProcessor(name, fn) {
    return this.get('i18next').addPostProcessor(name, fn);
  },

  /**
   * Forwarded to `i18next.applyReplacement()`.
   */
  applyReplacement(str, replacementHash, nestedKey, options) {
    return this.get('i18next').applyReplacement(str, replacementHash, nestedKey, options);
  },

  _initLibrary() {
    const i18next = this.get('i18next');
    const options = config.i18nextOptions || {};

    let errors;

    //
    //  TODO:  Adding i18nextXHRBackend by default so that translation
    //         files can be loaded.
    //         How do we extend this so that other plugins can be added
    //         dynamically?
    //
    return i18next
      .use(i18nextXHRBackend)
      .init(options, (err) => {
        if (err) errors = err;
      })
      .then(() => {
        if (errors) {
          return reject(errors);
        }
        else {
          return resolve(i18next);
        }
      });
  },

  _setLng(locale) {
    const i18next = this.get('i18next');
    return i18next.changeLanguage(locale)
      .then(() => resolve(locale));
  },

  _getActionCallHash(actions, lang) {
    const actionsCallHash = {};

    Object.keys(actions).forEach(key => {
      actionsCallHash[key] = actions[key].call(undefined, lang);
    });

    return actionsCallHash;
  },

  _runPreInitActions(newLang) {
    const _preInitActions = this.get('_preInitActions');
    const actionCalls = this._getActionCallHash(_preInitActions, newLang);

    return hash(actionCalls, 'ember-i18next: pre init actions');
  },

  _runPostInitActions(oldLang) {
    const _postInitActions = this.get('_postInitActions');
    const actionCalls = this._getActionCallHash(_postInitActions, oldLang);

    return hash(actionCalls, 'ember-i18next: post init actions');
  }
});

export default I18nService;
<commit_msg>Add `rejectError` config. It `true`, reject with errors.<commit_after>import { isBlank } from '@ember/utils';
import { assert } from '@ember/debug';
import {
  resolve,
  reject,
  hash
} from 'rsvp';
import { computed } from '@ember/object';
import Service from '@ember/service';
import i18next from 'i18next';
import i18nextXHRBackend from 'i18next-xhr-backend';

import config from 'ember-i18next/configuration';

/**
 * A service that exposes functionality from i18next.
 */
const I18nService = Service.extend({
  i18next: null,
  isInitialized: false,

  _locale: null,
  _preInitActions: null,
  _postInitActions: null,

  _errors: null,

  init() {
    this._super(...arguments);
    this.set('i18next', i18next);
    this.set('_preInitActions', {});
    this.set('_postInitActions', {});
  },

  /**
   * The current locale. This is a settable computed property; when set, the locale
   * will be changed using `i18next.setLng()` and registered pre- and post-init
   * actions will run. Finally, the locale will change, triggering a refresh of
   * localized text.
   */
  locale: computed('i18next', '_locale', {
    get() {
      return this.get('_locale');
    },
    set(key, value) {
      const lang = value;

      if (this.get('isInitialized')) {
        this._changeLocale(lang)
          .then(lang => this.set('_locale', lang));
      } else {
        this.set('_locale', lang);
      }

      return lang;
    }
  }),

  /**
   * Initializes the i18next library with configuration from the environment.
   *
   * @return {Promise} - a promise that resolves with the i18next object when
   *   i18next has finished initializing.
   */
  initLibraryAsync() {
    const i18next = this.get('i18next');
    const options = config.i18nextOptions || {};

    return this._runPreInitActions()
      .then(() => this._initLibrary())
      .then(() => this._runPostInitActions())
      .then(() => {
        this.set('_locale', i18next.language);
        this.set('isInitialized', true);
        return resolve();
      }).catch(reason => {
        // eslint-disable-next-line no-console
        console.warn(`A promise in the i18next init chain rejected with reason: ${reason}`);
        if (options.rejectError) {
          return reject(reason);
        }
      });
  },

  /**
   * Registers an action to execute before initializing i18next. Before initializing
   * the library or setting the language (which reinitializes the library), each of
   * the registered actions will be executed.
   *
   * If any pre-init actions return a promise, the service will wait until all the
   * promises have settled before initializing i18next.
   *
   * @param {String|Object} key -  the key to use to look up the action. May not be
   *   blank.
   * @param {Function} fn - a zero-argument callback function. Return a promise if
   *   the operation needs to complete before the i18next is initialized.
   */
  registerPreInitAction(key, fn) {
    assert('Pre-init action key may not be blank', !isBlank(key));
    assert('A pre-init action must be a function', typeof fn === 'function');
    this.get('_preInitActions')[key] = fn;
  },

  /**
   * Removes an action from the set of actions executed before initializing i18next.
   *
   * @param {String|Object} key - the key to use to look up the action to remove.
   *   May not be blank.
   */
  unregisterPreInitAction(key) {
    assert('Action key may not be blank', !isBlank(key));
    const preInitActions = this.get('_preInitActions');

    delete preInitActions[key];
  },

  /**
   * Registers an action to execute after initializing i18next. After initializing
   * the library or setting the language (which reinitializes the library), each of
   * the registered actions will be executed.
   *
   * If any post-init actions return a promise, the service will wait until all the
   * promises have settled before triggering a UI refresh.
   *
   * @param {String|Object} key -  the key to use to look up the action. May not be
   *   blank.
   * @param {Function} fn - a zero-argument callback function. Return a promise if
   *   the operation needs to complete before the the UI is refreshed.
   */
  registerPostInitAction(name, fn) {
    assert('Pre-init action name may not be blank', !isBlank(name));
    assert('A post-init action must be a function', typeof fn === 'function');
    this.get('_postInitActions')[name] = fn;
  },

  /**
   * Removes an action from the set of actions executed after initializing i18next.
   *
   * @param {String|Object} key - the key to use to look up the action to remove.
   *   May not be blank.
   */
  unregisterPostInitAction(key) {
    assert('Action key may not be blank', !isBlank(key));
    const postInitActions = this.get('_postInitActions');

    delete postInitActions[key];
  },

  /**
   * Changes the locale, ensuring that pre- and post-init actions run.
   *
   * @param {String} lang - locale code to set.
   *
   * @return {Promise} a promise that resolves with the language code when complete.
   */
  _changeLocale(lang) {
    const i18next = this.get('i18next');

    if (i18next && lang && i18next.language === lang) {
      return resolve(lang);
    }

    const oldLang = this._locale;
    return this._runPreInitActions(lang)
      .then(() => this._setLng(lang))
      .then(() => this._runPostInitActions(oldLang))
      .then(() => resolve(lang))
      .catch(reason => {
        // eslint-disable-next-line no-console
        console.warn(`A promise in the locale change path rejected with reason: ${reason}`);
      });
  },

  /**
   * Forwarded to `i18next.t()`.
   *
   * @param {String} path - an string that specifies the translation lookup key.
   *   Required.
   * @param {Object} values - an object that specifies values to substitute into
   *   the translation for the specified path. Optional.
   *
   * @return Localized text.
   */
  t(path, values) {
    const i18next = this.get('i18next');
    return i18next.t(path, values);
  },

  /**
   * Forwarded to `i18next.addResourceBundle()`.
   */
  addResourceBundle(lang, ns, resources, deep, overwrite) {
    return this.get('i18next').addResourceBundle(lang, ns, resources, deep, overwrite);
  },

  /**
   * Forwarded to `i18next.hasResourceBundle()`.
   */
  hasResourceBundle(lang, ns) {
    return this.get('i18next').hasResourceBundle(lang, ns);
  },

  /**
   * Forwarded to `i18next.getResourceBundle()`.
   */
  getResourceBundle(lang, ns) {
    return this.get('i18next').getResourceBundle(lang, ns);
  },

  /**
   * Forwarded to `i18next.removeResourceBundle()`.
   */
  removeResourceBundle(lang, ns) {
    return this.get('i18next').removeResourceBundle(lang, ns);
  },

  /**
   * Forwarded to `i18next.addResource()`.
   */
  addResource(lang, ns, key, value, options) {
    return this.get('i18next').addResource(lang, ns, key, value, options);
  },

  /**
   * Forwarded to `i18next.addResources()`.
   */
  addResources(lang, ns, resources) {
    return this.get('i18next').addResources(lang, ns, resources);
  },

  /**
   * Forwarded to `i18next.loadNamespaces()`.
   */
  loadNamespaces(namespaces, callback) {
    return this.get('i18next').loadNamespaces(namespaces, callback);
  },

  /**
   * Forwarded to `i18next.setDefaultNamespace()`.
   */
  setDefaultNamespace(ns) {
    return this.get('i18next').setDefaultNamespace(ns);
  },

  /**
   * Alias for `t()`.
   */
  translate(key, values) {
    return this.t(key, values);
  },

  /**
   * Forwarded to `i18next.exists()`.
   */
  exists(key, options) {
    return this.get('i18next').exists(key, options);
  },

  /**
   * Gets i18next's `pluralExtensions` property.
   */
  pluralExtensions: computed('i18next', function () {
    return this.get('i18next').pluralExtensions;
  }),

  /**
   * Forwarded to `i18next.addPostProcessor()`.
   */
  addPostProcessor(name, fn) {
    return this.get('i18next').addPostProcessor(name, fn);
  },

  /**
   * Forwarded to `i18next.applyReplacement()`.
   */
  applyReplacement(str, replacementHash, nestedKey, options) {
    return this.get('i18next').applyReplacement(str, replacementHash, nestedKey, options);
  },

  _initLibrary() {
    const i18next = this.get('i18next');
    const options = config.i18nextOptions || {};

    let errors;

    //
    //  TODO:  Adding i18nextXHRBackend by default so that translation
    //         files can be loaded.
    //         How do we extend this so that other plugins can be added
    //         dynamically?
    //
    return i18next
      .use(i18nextXHRBackend)
      .init(options, (err) => {
        if (err) errors = err;
      })
      .then(() => {
        if (errors) {
          return reject(errors);
        }
        else {
          return resolve(i18next);
        }
      });
  },

  _setLng(locale) {
    const i18next = this.get('i18next');
    return i18next.changeLanguage(locale)
      .then(() => resolve(locale));
  },

  _getActionCallHash(actions, lang) {
    const actionsCallHash = {};

    Object.keys(actions).forEach(key => {
      actionsCallHash[key] = actions[key].call(undefined, lang);
    });

    return actionsCallHash;
  },

  _runPreInitActions(newLang) {
    const _preInitActions = this.get('_preInitActions');
    const actionCalls = this._getActionCallHash(_preInitActions, newLang);

    return hash(actionCalls, 'ember-i18next: pre init actions');
  },

  _runPostInitActions(oldLang) {
    const _postInitActions = this.get('_postInitActions');
    const actionCalls = this._getActionCallHash(_postInitActions, oldLang);

    return hash(actionCalls, 'ember-i18next: post init actions');
  }
});

export default I18nService;
<|endoftext|>


<commit_before>const fs = require('fs');
const rest = require('unirest');
const TEST = 0;

class Context {

    prompts() {
        return [{ name: 'address', type: 'list', message: 'Select service', lookup: 'service.all' }];
    }

    init(options) {
        let self = this;
        if (TEST) {
            var info = JSON.parse(fs.readFileSync("admin-on-rest/test.json"));
            self.schemas = self.prepareSchemas(info.value.services, info.value.schemas);
            return Promise.resolve();
        }

        return new Promise((resolve, reject) => {
            try {
                let request = rest.get(options.address)
                    .header('Accept', 'application/json')
                    .type("json");

                this.sendRequest(request).then(function (response) {
                    if (response.ok) {
                        var info = response.body;
                        if (info.error && info.error.message) {
                            reject(info.error.message);
                            return;
                        }
                        self.schemas = self.prepareSchemas(info.value.services, info.value.schemas);

                        resolve(self.camelCase(self.normalizeService(info.value.serviceName)) + ".js");
                    }
                    else {
                        reject("Invalid service address : " + response.error.message);
                    }
                });
            }
            catch (e) {
                reject(e);
            }
        });
    }

    getFieldComponent(prop) {
        if (prop.custom && prop.custom.reference) {
            return `<ReferenceField label="${prop.custom.reference}" source="${prop.name}" reference="${prop.custom.reference}">
                <TextField source="${prop.custom.referenceField}" />
            </ReferenceField>`;
        }
        if (prop.metadata.type === "enum") {
            return `<ChipField source="${prop.name}" />`;
        }
        if (prop.metadata.type === "date") {
            return `<DateField source="${prop.name}" />`;
        }

        if(prop.type === "number")
            return `<NumberField source="${prop.name}" />`;

        return `<TextField source="${prop.name}"/>`;
    }

    getInputComponent(schema, prop, editMode) {
        var opts = prop.required ? " validate={[required ]}" : "";
        if (prop.name === schema.idProperty) {
            if (prop.metadata.type === "uid" && !editMode)
                return "";

            if(editMode) return `<DisabledInput source="${prop.name}" ${opts}/>`;
        }

        if (prop.custom && prop.custom.reference) {
            var html = `<ReferenceInput label="${prop.custom.reference}" source="${prop.name}"
                    reference="${prop.custom.reference}" ${prop.required && !editMode ? "" : "allowEmpty"} `;
            if (prop.custom.referenceFilter) {
                html += `{${JSON.stringify(prop.custom.referenceFilter)}}`
            }
            html += `>
                <SelectInput source="${prop.custom.referenceField}" />
            </ReferenceInput>`;
            return html;
        }
        if (prop.metadata.type === "enum") {
            return `<SelectInput source="${prop.name}" choices={${JSON.stringify(prop.metadata.values)}} />`;
        }

        if (prop.metadata.type === "date") {
            return `<DateInput source="${prop.name}" />`;
        }

        if(prop.type === "number")
            return `<NumberInput source="${prop.name}"  ${opts}/>`;

        return `<TextInput source="${prop.name}"  ${opts}/>`;
    }

    sendRequest(request) {
        return new Promise((resolve) => {
            request.end(resolve);
        })
    }

    prepareSchemas(services, schemas) {
        let result = {};

        for (let srv of services) {
            let schemaName = srv.schema;
            if (!schemaName || result[schemaName])
                continue;
            let schema = schemas.find(s => s.name === schemaName);
            result[schemaName] = schema;
        }
        return result;
    }

    camelCase(name) {
        return name[0].toLowerCase() + name.substr(1);
    }

    pascalCase(name) {
        return name[0].toUpperCase() + name.substr(1);
    }

    normalizeService(name) {
        let parts = name.split(/[\._-]/);
        let result = this.pascalCase(parts[0]);
        for (let i = 1; i < parts.length; i++) {
            result += this.pascalCase(parts[i]);
        }
        return (result + "Service").replace(/-/g, '');
    }
}

exports.Context = Context;
<commit_msg>update template<commit_after>const fs = require('fs');
const rest = require('unirest');
const TEST = 0;

class Context {

    prompts() {
        return [{ name: 'address', type: 'list', message: 'Select service', lookup: 'service.all' }];
    }

    init(options) {
        let self = this;
        if (TEST) {
            var info = JSON.parse(fs.readFileSync("admin-on-rest/test.json"));
            self.schemas = self.prepareSchemas(info.value.services, info.value.schemas);
            return Promise.resolve();
        }

        return new Promise((resolve, reject) => {
            try {
                let request = rest.get(options.address)
                    .header('Accept', 'application/json')
                    .type("json");

                this.sendRequest(request).then(function (response) {
                    if (response.ok) {
                        var info = response.body;
                        if (info.error && info.error.message) {
                            reject(info.error.message);
                            return;
                        }
                        self.schemas = self.prepareSchemas(info.value.services, info.value.schemas);

                        resolve(self.camelCase(self.normalizeService(info.value.serviceName)) + ".js");
                    }
                    else {
                        reject("Invalid service address : " + response.error.message);
                    }
                });
            }
            catch (e) {
                reject(e);
            }
        });
    }

    getFieldComponent(prop) {
        if (prop.custom && prop.custom.reference) {
            return `<ReferenceField label="${prop.custom.reference}" source="${prop.name}" reference="${prop.custom.reference}">
                <TextField source="${prop.custom.referenceField}" />
            </ReferenceField>`;
        }
        if (prop.metadata.type === "enum") {
            return `<ChipField source="${prop.name}" />`;
        }
        if (prop.metadata.type === "date") {
            return `<DateField source="${prop.name}" />`;
        }

        if(prop.type === "number")
            return `<NumberField source="${prop.name}" />`;

        return `<TextField source="${prop.name}"/>`;
    }

    getInputComponent(schema, prop, editMode) {
        var opts = prop.required ? " validate={[required ]}" : "";
        if (prop.name === schema.idProperty) {
            if (prop.metadata.type === "uid" && !editMode)
                return "";

            if(editMode) return `<DisabledInput source="${prop.name}" ${opts}/>`;
        }

        if (prop.custom && prop.custom.reference) {
            var html = `<ReferenceInput label="${prop.custom.reference}" source="${prop.name}"
                    reference="${prop.custom.reference}" ${(prop.required && !editMode) ? "" : "allowEmpty"} `;
            if (prop.custom.referenceFilter) {
                html += `filter={${JSON.stringify(prop.custom.referenceFilter)}}`
            }
            html += `>
                <SelectInput source="${prop.custom.referenceField}" />
            </ReferenceInput>`;
            return html;
        }
        if (prop.metadata.type === "enum") {
            let choices = prop.metadata.values.map(c => { id: c; name: c });
            return `<SelectInput source="${prop.name}" choices={${JSON.stringify(choices)}} />`;
        }

        if (prop.metadata.type === "date") {
            return `<DateInput source="${prop.name}" />`;
        }

        if(prop.type === "number")
            return `<NumberInput source="${prop.name}"  ${opts}/>`;

        return `<TextInput source="${prop.name}"  ${opts}/>`;
    }

    sendRequest(request) {
        return new Promise((resolve) => {
            request.end(resolve);
        })
    }

    prepareSchemas(services, schemas) {
        let result = {};

        for (let srv of services) {
            let schemaName = srv.schema;
            if (!schemaName || result[schemaName])
                continue;
            let schema = schemas.find(s => s.name === schemaName);
            result[schemaName] = schema;
        }
        return result;
    }

    camelCase(name) {
        return name[0].toLowerCase() + name.substr(1);
    }

    pascalCase(name) {
        return name[0].toUpperCase() + name.substr(1);
    }

    normalizeService(name) {
        let parts = name.split(/[\._-]/);
        let result = this.pascalCase(parts[0]);
        for (let i = 1; i < parts.length; i++) {
            result += this.pascalCase(parts[i]);
        }
        return (result + "Service").replace(/-/g, '');
    }
}

exports.Context = Context;
<|endoftext|>


<commit_before>import fs from 'fs';
import json2csv from 'json2csv';
import { ArgumentParser } from 'argparse';

import emailLib from '../server/lib/email';
import { promiseSeq } from '../server/lib/utils';
import { sequelize } from '../server/models';
import {
  ordersWithPendingCharges,
  processOrderWithSubscription,
} from '../server/lib/subscriptions';

const REPORT_EMAIL = 'ops@opencollective.com';

// These field names are the ones returned by
// processOrderWithSubscription().
const csvFields = [
  'orderId',
  'subscriptionId',
  'amount',
  'from',
  'to',
  'status',
  'error',
  'retriesBefore',
  'retriesAfter',
  'chargeDateBefore',
  'chargeDateAfter',
  'nextPeriodStartBefore',
  'nextPeriodStartAfter'
];

/** Run the script with parameters read from the command line */
async function run(options) {
  const start = new Date;
  const orders = await ordersWithPendingCharges();
  vprint(options, `${orders.length} subscriptions pending charges. dryRun: ${options.dryRun}`);
  const data = [];
  await promiseSeq(orders, async (order) => {
    vprint(options,
           `order: ${order.id}, subscription: ${order.Subscription.id}, ` +
           `attempt: #${order.Subscription.chargeRetryCount}, ` +
           `due: ${order.Subscription.nextChargeDate}`);
    data.push(await processOrderWithSubscription(options, order));
  }, options.batchSize);

  if (data.length > 0) {
    await json2csv({ data, fields: csvFields }, async (err, csv) => {
      vprint(options, 'Writing the output to a CSV file');
      if (err) console.log(err);
      else {
        if (options.dryRun) {
          fs.writeFileSync('charge_subscriptions.output.csv', csv);
        } else {
          if (!options.dryRun) {
            vprint(options, 'Sending email report');
            const attachments = [{
              filename: `${(new Date).toLocaleDateString()}.csv`,
              content: csv
            }];
            await emailReport(start, orders, data, attachments);
          }
        }
      }
    });
  } else {
    vprint(options, 'Not generating CSV file');
  }
}

/** Send an email with details of the subscriptions processed */
async function emailReport(start, orders, data, attachments) {
  const icon = (err) => err ? '❌' : '✅';
  let issuesFound = false;
  let result = [`Total Subscriptions pending charges found: ${orders.length}`, ''];

  result = result.concat(data.map((i) => {
    if (i.status === 'failure') issuesFound = true;
    return ` ${i.status !== 'unattempted' ? icon(i.error) : ''} ` + [
      `order: ${i.orderId}`,
      `subscription: ${i.subscriptionId}`,
      `amount: ${i.amount}`,
      `from: ${i.from}`,
      `to: ${i.to}`,
      `status: ${i.status}`,
      `error: ${i.error}`,
    ].join(', ');
  }));

  const now = new Date;
  const end = now - start;
  result.push(`\n\nTotal time taken: ${end}ms`);
  const subject = `${icon(issuesFound)} Daily Subscription Report - ${now.toLocaleDateString()}`;
  return emailLib.sendMessage(REPORT_EMAIL, subject, '', {
    bcc: ' ',
    text: result.join('\n'),
    attachments
  });
}

/** Print `message` to console if `options.verbose` is true */
function vprint(options, message) {
  if (options.verbose) {
    console.log(message);
  }
}

/** Return the options passed by the user to run the script */
function parseCommandLineArguments() {
  const parser = new ArgumentParser({
    addHelp: true,
    description: 'Charge due subscriptions',
  });
  parser.addArgument(['-v', '--verbose'], {
    help: 'Verbose output',
    defaultValue: false,
    action: 'storeConst',
    constant: true,
  });
  parser.addArgument(['--notdryrun'], {
    help: "Pass this flag when you're ready to run the script for real",
    defaultValue: false,
    action: 'storeConst',
    constant: true,
  });
  parser.addArgument(['-b', '--batch_size'], {
    help: 'batch size to fetch at a time',
    defaultValue: 10
  });
  const args = parser.parseArgs();
  return {
    dryRun: !args.notdryrun,
    verbose: args.verbose,
    batchSize: args.batch_size || 100
  };
}

/** Kick off the script with all the user selected options */
async function entryPoint(options) {
  vprint(options, 'Starting to charge subscriptions');
  try {
    await run(options);
  } finally {
    await sequelize.close();
  }
  vprint(options, 'Finished running charge subscriptions');
}

/* Entry point */
entryPoint(parseCommandLineArguments());
<commit_msg>scripts/charge_subscriptions: Add `limit' flag to do partial runs (#1145)<commit_after>import fs from 'fs';
import json2csv from 'json2csv';
import { ArgumentParser } from 'argparse';

import emailLib from '../server/lib/email';
import { promiseSeq } from '../server/lib/utils';
import { sequelize } from '../server/models';
import {
  ordersWithPendingCharges,
  processOrderWithSubscription,
} from '../server/lib/subscriptions';

const REPORT_EMAIL = 'ops@opencollective.com';

// These field names are the ones returned by
// processOrderWithSubscription().
const csvFields = [
  'orderId',
  'subscriptionId',
  'amount',
  'from',
  'to',
  'status',
  'error',
  'retriesBefore',
  'retriesAfter',
  'chargeDateBefore',
  'chargeDateAfter',
  'nextPeriodStartBefore',
  'nextPeriodStartAfter'
];

/** Run the script with parameters read from the command line */
async function run(options) {
  const start = new Date;
  const allOrders = await ordersWithPendingCharges();
  const orders = (options.limit) ? allOrders.slice(0, options.limit) : allOrders;
  vprint(options, `${allOrders.length} subscriptions pending charges. Charging ${orders.length} subscriptions right now. dryRun: ${options.dryRun}`);
  const data = [];
  await promiseSeq(orders, async (order) => {
    vprint(options,
           `order: ${order.id}, subscription: ${order.Subscription.id}, ` +
           `attempt: #${order.Subscription.chargeRetryCount}, ` +
           `due: ${order.Subscription.nextChargeDate}`);
    data.push(await processOrderWithSubscription(options, order));
  }, options.batchSize);

  if (data.length > 0) {
    await json2csv({ data, fields: csvFields }, async (err, csv) => {
      vprint(options, 'Writing the output to a CSV file');
      if (err) console.log(err);
      else {
        if (options.dryRun) {
          fs.writeFileSync('charge_subscriptions.output.csv', csv);
        } else {
          if (!options.dryRun) {
            vprint(options, 'Sending email report');
            const attachments = [{
              filename: `${(new Date).toLocaleDateString()}.csv`,
              content: csv
            }];
            await emailReport(start, orders, data, attachments);
          }
        }
      }
    });
  } else {
    vprint(options, 'Not generating CSV file');
  }
}

/** Send an email with details of the subscriptions processed */
async function emailReport(start, orders, data, attachments) {
  const icon = (err) => err ? '❌' : '✅';
  let issuesFound = false;
  let result = [`Total Subscriptions pending charges found: ${orders.length}`, ''];

  result = result.concat(data.map((i) => {
    if (i.status === 'failure') issuesFound = true;
    return ` ${i.status !== 'unattempted' ? icon(i.error) : ''} ` + [
      `order: ${i.orderId}`,
      `subscription: ${i.subscriptionId}`,
      `amount: ${i.amount}`,
      `from: ${i.from}`,
      `to: ${i.to}`,
      `status: ${i.status}`,
      `error: ${i.error}`,
    ].join(', ');
  }));

  const now = new Date;
  const end = now - start;
  result.push(`\n\nTotal time taken: ${end}ms`);
  const subject = `${icon(issuesFound)} Daily Subscription Report - ${now.toLocaleDateString()}`;
  return emailLib.sendMessage(REPORT_EMAIL, subject, '', {
    bcc: ' ',
    text: result.join('\n'),
    attachments
  });
}

/** Print `message` to console if `options.verbose` is true */
function vprint(options, message) {
  if (options.verbose) {
    console.log(message);
  }
}

/** Return the options passed by the user to run the script */
function parseCommandLineArguments() {
  const parser = new ArgumentParser({
    addHelp: true,
    description: 'Charge due subscriptions',
  });
  parser.addArgument(['-v', '--verbose'], {
    help: 'Verbose output',
    defaultValue: false,
    action: 'storeConst',
    constant: true,
  });
  parser.addArgument(['--notdryrun'], {
    help: "Pass this flag when you're ready to run the script for real",
    defaultValue: false,
    action: 'storeConst',
    constant: true,
  });
  parser.addArgument(['-l', '--limit'], {
    help: 'total subscriptions to process'
  });
  parser.addArgument(['-b', '--batch_size'], {
    help: 'batch size to fetch at a time',
    defaultValue: 10
  });
  const args = parser.parseArgs();
  return {
    dryRun: !args.notdryrun,
    verbose: args.verbose,
    limit: args.limit,
    batchSize: args.batch_size || 100
  };
}

/** Kick off the script with all the user selected options */
async function entryPoint(options) {
  vprint(options, 'Starting to charge subscriptions');
  try {
    await run(options);
  } finally {
    await sequelize.close();
  }
  vprint(options, 'Finished running charge subscriptions');
}

/* Entry point */
entryPoint(parseCommandLineArguments());
<|endoftext|>