<commit_before>/* eslint-disable import/extensions */

const path = require('path');
const Webpack = require('webpack');

const LIB_CONFIG = require('../lib/lib.config.js');
const LIB_PATHS = require('../lib/paths.config.js');
const PACKAGE = require('../../package.json');

module.exports = (env) => {

  /*
   * constants
   */

  const BABEL_CONFIG = path.resolve(__dirname, '../babel/babel.config.js');
  const ENV_DEV = 'development';
  const ENV_PROD = 'production';
  const LIB_FILE_NAME = 'lattice.js';
  const LIB_NAMESPACE = 'Lattice';

  /*
   * loaders
   */

  const BABEL_LOADER = {
    test: /\.js$/,
    exclude: /node_modules/,
    include: [
      LIB_PATHS.ABS.SOURCE,
    ],
    use: {
      loader: 'babel-loader',
      options: {
        configFile: BABEL_CONFIG,
      },
    },
  };

  /*
   * plugins
   */

  const BANNER_PLUGIN = new Webpack.BannerPlugin({
    banner: LIB_CONFIG.BANNER,
    entryOnly: true,
  });

  const DEFINE_PLUGIN = new Webpack.DefinePlugin({
    __ENV_DEV__: JSON.stringify(!!env.development),
    __ENV_PROD__: JSON.stringify(!!env.production),
    __PACKAGE__: JSON.stringify(PACKAGE.name),
    __VERSION__: JSON.stringify(`v${PACKAGE.version}`),
  });

  /*
   * base webpack config
   */

  return {
    bail: true,
    entry: [
      '@babel/polyfill', // TODO: figure out if this is necessary
      LIB_PATHS.ABS.ENTRY,
    ],
    mode: env.production ? ENV_PROD : ENV_DEV,
    module: {
      rules: [
        BABEL_LOADER,
      ],
    },
    optimization: {
      minimize: !!env.production,
    },
    output: {
      library: LIB_NAMESPACE,
      libraryTarget: 'umd',
      path: LIB_PATHS.ABS.BUILD,
      publicPath: '/',
      filename: LIB_FILE_NAME,
    },
    performance: {
      hints: false, // disable performance hints for now
    },
    plugins: [
      DEFINE_PLUGIN,
      BANNER_PLUGIN,
    ],
    resolve: {
      extensions: ['.js'],
      modules: [
        LIB_PATHS.ABS.SOURCE,
        LIB_PATHS.ABS.NODE,
      ]
    },
    target: 'web',
  };
};
<commit_msg>ignore moment locales<commit_after>/* eslint-disable import/extensions */

const path = require('path');
const Webpack = require('webpack');

const LIB_CONFIG = require('../lib/lib.config.js');
const LIB_PATHS = require('../lib/paths.config.js');
const PACKAGE = require('../../package.json');

module.exports = (env) => {

  /*
   * constants
   */

  const BABEL_CONFIG = path.resolve(__dirname, '../babel/babel.config.js');
  const ENV_DEV = 'development';
  const ENV_PROD = 'production';
  const LIB_FILE_NAME = 'lattice.js';
  const LIB_NAMESPACE = 'Lattice';

  /*
   * loaders
   */

  const BABEL_LOADER = {
    test: /\.js$/,
    exclude: /node_modules/,
    include: [
      LIB_PATHS.ABS.SOURCE,
    ],
    use: {
      loader: 'babel-loader',
      options: {
        configFile: BABEL_CONFIG,
      },
    },
  };

  /*
   * plugins
   */

  const BANNER_PLUGIN = new Webpack.BannerPlugin({
    banner: LIB_CONFIG.BANNER,
    entryOnly: true,
  });

  const DEFINE_PLUGIN = new Webpack.DefinePlugin({
    __ENV_DEV__: JSON.stringify(!!env.development),
    __ENV_PROD__: JSON.stringify(!!env.production),
    __PACKAGE__: JSON.stringify(PACKAGE.name),
    __VERSION__: JSON.stringify(`v${PACKAGE.version}`),
  });

  // https://github.com/moment/moment/issues/2373
  // https://stackoverflow.com/a/25426019/196921
  // https://github.com/facebookincubator/create-react-app/pull/2187
  const IGNORE_MOMENT_LOCALES = new Webpack.IgnorePlugin(/^\.\/locale$/, /moment$/);

  /*
   * base webpack config
   */

  return {
    bail: true,
    entry: [
      '@babel/polyfill', // TODO: figure out if this is necessary
      LIB_PATHS.ABS.ENTRY,
    ],
    mode: env.production ? ENV_PROD : ENV_DEV,
    module: {
      rules: [
        BABEL_LOADER,
      ],
    },
    optimization: {
      minimize: !!env.production,
    },
    output: {
      library: LIB_NAMESPACE,
      libraryTarget: 'umd',
      path: LIB_PATHS.ABS.BUILD,
      publicPath: '/',
      filename: LIB_FILE_NAME,
    },
    performance: {
      hints: false, // disable performance hints for now
    },
    plugins: [
      DEFINE_PLUGIN,
      BANNER_PLUGIN,
      IGNORE_MOMENT_LOCALES,
    ],
    resolve: {
      extensions: ['.js'],
      modules: [
        LIB_PATHS.ABS.SOURCE,
        LIB_PATHS.ABS.NODE,
      ]
    },
    target: 'web',
  };
};
<|endoftext|>


<commit_before>define([
    "dojo/_base/declare",
    "dojo/text!./template/ImageDiscoveryTemplate.html",
    "xstyle/css!./theme/ImageDiscoveryTheme.css",
    "dojo/topic",
    "dojo/has",
    'dijit/layout/ContentPane',
    "dojo/_base/lang",
    "dojo/dom-style",
    "dojo/dom-class",
    "esriviewer/ui/base/UITemplatedWidget",
    "esriviewer/ui/draw/base/MapDrawSupport",
    "dojo/_base/Color",
    "../discover/upload/GeometryUploadWidget",
    "./SearchByBoundsWidget",
    "../query/ImageQueryWidget",
    "./model/ImageDiscoveryViewModel",
    "dijit/form/NumberTextBox",
    "esri/symbols/SimpleFillSymbol",
    "esri/symbols/SimpleMarkerSymbol",
    "esri/symbols/SimpleLineSymbol",
    "esri/graphic",
    "esri/geometry/Geometry",
    "esri/geometry/Point",
    "esri/geometry/Polygon",
    "esri/geometry/Extent",
    "../../base/ImageQueryLayerControllerQueryParameters"
],
    function (declare, template,theme, topic, has, ContentPane, lang, domStyle, domClass, UITemplatedWidget, MapDrawSupport, Color, GeometryUploadWidget, SearchByBoundsWidget, ImageQueryWidget, ImageDiscoveryViewModel, NumberTextBox, SimpleFillSymbol, SimpleMarkerSymbol, SimpleLineSymbol, Graphic, Geometry, Point, Polygon, Extent, ImageQueryLayerControllerQueryParameters) {
        return declare(
            [ContentPane, UITemplatedWidget, MapDrawSupport],
            {
                createQueryFieldsDiscoveryContent: false,
                title: "Discover",
                templateString: template,
                constructor: function (params) {
                    lang.mixin(this, params || {});
                    this.currentAddedGraphics = [];
                },
                postCreate: function () {
                    this.inherited(arguments);
                    this.searchByGeometryGeometryQueryErrorback = lang.hitch(this,this.handleSearchByGeometryGeometryQueryError);
                    this.performSearchCallback = lang.hitch(this, this.performSearch);
                    this.viewModel = new ImageDiscoveryViewModel();
                    this.viewModel.on("firstBoundsDisplay", lang.hitch(this, this.createBoundsView));
                    this.viewModel.on("viewChange", lang.hitch(this, this.handleViewChanged));
                    this.viewModel.discoverByFieldsExpanded.subscribe(lang.hitch(this,this.handleDiscoveryByFieldsToggle));
                    this.initSymbology();
                    if (this.createQueryFieldsDiscoveryContent) {
                        this.viewModel.selectedDiscoveryService.subscribe(lang.hitch(this, this.handleSearchServiceChanged));
                    }
                    ko.applyBindings(this.viewModel, this.domNode);
                    if (this.discoverGeometryUploadTaskConfiguration == null || !lang.isObject(this.discoverGeometryUploadTaskConfiguration)) {
                        this.viewModel.searchByGeometryButtonVisible(false);

                    }
                    else {
                        this.createUploadView();
                    }
                    if (this.createQueryFieldsDiscoveryContent) {
                        this.createQueryView();
                    }
                },
                handleDiscoveryByFieldsToggle: function (expanded) {
                    //toggle the view for searching by field value in the discovery widget
                    if (!expanded && this.imageQueryWidget) {
                        this.imageQueryWidget.closePopups();
                    }
                },
                initListeners: function () {
                    //listen for when the accordion has been hiden
                    topic.subscribe(VIEWER_GLOBALS.EVENTS.TOOLS.ACCORDION.HIDE_COMPLETE, lang.hitch(this, this.handleAccordionHidden));
                    //listen for when all query layer controllers have been loaded
                    topic.subscribe(IMAGERY_GLOBALS.EVENTS.QUERY.LAYER_CONTROLLERS.LOADED, lang.hitch(this, this.handleQueryLayerControllersLoaded));
                    this.on("annotationCreated", lang.hitch(this, this.handleAnnotationAddedFromUser));
                    this.on("show", lang.hitch(this, this.handleOnShow));
                    //listen for clear results
                    topic.subscribe(IMAGERY_GLOBALS.EVENTS.QUERY.RESULT.CLEAR, lang.hitch(this, this.handleResultsCleared));
                },
                handleSearchServiceChanged: function (queryController) {
                    //when search service changed the unique values need to be reloaded
                    if (this.imageQueryWidget) {
                        if (queryController == null) {
                            this.hideUniqueValuesContent();
                        }
                        else {
                            this.viewModel.discoverByFieldsHeaderVisible(true);
                            this.imageQueryWidget.setCurrentQueryLayerController(queryController)
                        }
                    }
                },
                handleQueryLayerControllersLoaded: function (queryLayerControllers) {
                    var currentQueryLayerController;
                    var currentQueryLayer;
                    this.queryLayerControllers = queryLayerControllers;
                    if (queryLayerControllers.length == 1) {
                        this.viewModel.selectSearchServiceVisible(false);
                        if (this.createQueryFieldsDiscoveryContent) {
                            this.viewModel.discoverByFieldsHeaderVisible(true);
                           this.handleSearchServiceChanged(queryLayerControllers[0]);
                        }
                    }
                    else {
                        this.viewModel.selectSearchServiceVisible(true);
                        for (var i = 0; i < queryLayerControllers.length; i++) {
                            currentQueryLayerController = queryLayerControllers[i];
                            currentQueryLayer = (currentQueryLayerController && currentQueryLayerController.layer) ? currentQueryLayerController.layer : null;
                            if (currentQueryLayerController && currentQueryLayer) {
                                this.viewModel.discoveryServicesList.push({label: currentQueryLayer.searchServiceLabel, value: currentQueryLayerController});
                            }
                        }
                    }
                },
                hideUniqueValuesContent: function () {
                    //hide unique values view
                    this.viewModel.discoverByFieldsExpanded(false);
                    this.viewModel.discoverByFieldsHeaderVisible(false);
                },
                createQueryView: function () {
                    //create the view which shows unique values for the active service
                    this.imageQueryWidget = new ImageQueryWidget();
                    this.imageQueryWidget.on("noUniqueValuesReturned", lang.hitch(this, this.hideUniqueValuesContent));
                    this.imageQueryWidget.placeAt(this.imageDiscoveryByQueryContainer);
                },
                loadViewerConfigurationData: function () {
                    //load the configuration
                    var discoveryGeometryUploadConfiguration;
                    topic.publish(IMAGERY_GLOBALS.EVENTS.CONFIGURATION.GET_ENTRY, "discoverGeometryUploadTask", function (discoveryGeometryUploadConf) {
                        discoveryGeometryUploadConfiguration = discoveryGeometryUploadConf;
                    });
                    if (discoveryGeometryUploadConfiguration != null && lang.isObject(discoveryGeometryUploadConfiguration)) {
                        this.discoverGeometryUploadTaskConfiguration = discoveryGeometryUploadConfiguration;
                    }
                    var discoveryQueryFields;
                    topic.publish(IMAGERY_GLOBALS.EVENTS.CONFIGURATION.GET_ENTRY, "imageDiscoveryQueryFields", function (discoveryQueryFieldsConf) {
                        discoveryQueryFields = discoveryQueryFieldsConf;
                    });
                    if (discoveryQueryFields != null && lang.isArray(discoveryQueryFields) && discoveryQueryFields.length > 0) {
                        this.createQueryFieldsDiscoveryContent = !(has("ie") == 7);
                    }
                },
                handleSearchByGeometryGeometryQueryError: function (msg) {
                    this.clearDraw();
                },
                initSymbology: function () {
                    //init the discovery widget symbology
                    this.polygonSymbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
                            new Color([0, 0, 255]), 1), new Color([0, 0, 255, 0]));

                    this.pointSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_X, 1,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
                            new Color("blue")));

                    this.envelopeSymbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
                            new Color([0, 0, 255]), 1),
                        new Color([0, 0, 0, 0]));
                },
                handleAccordionHidden: function () {
                    if (this.imageQueryWidget) {
                        this.imageQueryWidget.closePopups();

                    }
                },
                handleOnShow: function () {
                    //fire event telling other widgets the discovery widget has come into view
                    topic.publish(IMAGERY_GLOBALS.EVENTS.DISCOVERY.ON_SHOW);
                },
                handleResultsCleared: function () {
                    //when results are cleared remove and geometries left over from the initial search
                    this.clearVisibileGraphics();
                },
                clearVisibileGraphics: function () {
                    //clears any graphics on the map created from the discovery widget
                    if (this.currentAddedGraphics) {
                        for (var i = 0; i < this.currentAddedGraphics.length; i++) {
                            topic.publish(VIEWER_GLOBALS.EVENTS.MAP.GRAPHICS.REMOVE, this.currentAddedGraphics[i]);

                        }
                    }
                    this.currentAddedGraphics = [];
                },
                activateSearchByExtent: function () {
                    //searches by map extent
                    var mapExtent = null;
                    topic.publish(VIEWER_GLOBALS.EVENTS.MAP.EXTENT.GET_EXTENT, function (ext) {
                        mapExtent = ext;
                    });
                    if (mapExtent == null) {
                        return;
                    }
                    this.performSearch(mapExtent, false);
                },
                performSearch: function (searchObject, zoomToArea) {
                   //figure out what type of search is being performed and perform the search
                    if (searchObject == null) {
                        return;
                    }
                    //searchObject can either be a graphic,geometry or array of geometries
                    var graphic;
                    var whereClause = "";
                    if (this.imageQueryWidget != null && this.viewModel.discoverByFieldsExpanded()) {
                        whereClause = this.imageQueryWidget.getQuery();
                    }

                    //clear the previous result
                    topic.publish(IMAGERY_GLOBALS.EVENTS.QUERY.RESULT.CLEAR);
                    //get the services to query
                    var queryLayerControllers;
                    var selectedDiscoveryService = this.viewModel.selectedDiscoveryService();
                    if (selectedDiscoveryService) {
                        queryLayerControllers = [selectedDiscoveryService];
                    }
                    else {
                        queryLayerControllers = this.queryLayerControllers;
                    }
                    var imageQueryParameters = new ImageQueryLayerControllerQueryParameters({
                        queryLayerControllers: queryLayerControllers,
                        whereClause: whereClause,
                        returnGeometry: true
                    });
                    var searchGraphic;
                    //figure out if the search object is already a graphic or if it is a geometry that needs to be turned into a graphic
                    if (searchObject instanceof Graphic) {
                        searchGraphic = searchObject;
                        this.currentAddedGraphics.push(searchObject);
                    }
                    else if (searchObject instanceof Geometry) {
                        graphic = null;
                        if (searchObject instanceof Point) {
                            graphic = new Graphic(searchObject, this.pointSymbol);
                        }
                        else if (searchObject instanceof Polygon) {
                            graphic = new Graphic(searchObject, this.polygonSymbol);
                        }
                        else if (searchObject instanceof Extent) {
                            graphic = new Graphic(searchObject, this.polygonSymbol);
                        }
                        if (graphic) {
                            this.currentAddedGraphics.push(graphic);
                            //add the graphic to the map
                            topic.publish(VIEWER_GLOBALS.EVENTS.MAP.GRAPHICS.ADD, graphic);
                            searchGraphic = graphic;
                        }

                    }
                    imageQueryParameters.geometry = searchGraphic.geometry;
                    imageQueryParameters.errback = this.searchByGeometryGeometryQueryErrorback;
                    topic.publish(IMAGERY_GLOBALS.EVENTS.QUERY.SEARCH.GEOMETRY, imageQueryParameters);
                },
                handleViewChanged: function (oldView, newView) {
                    //figure out what view we are in and publish draw events accordingly
                    if (oldView == newView && newView != this.viewModel.views.extent) {
                        return;
                    }
                    if (newView == this.viewModel.views.point) {
                        this.setDraw(VIEWER_GLOBALS.EVENTS.MAP.TOOLS.DRAW_POINT);
                    }
                    else if (newView == this.viewModel.views.rectangle) {
                        this.setDraw(VIEWER_GLOBALS.EVENTS.MAP.TOOLS.DRAW_RECTANGLE);

                    }
                    else if (newView == this.viewModel.views.extent) {
                        this.activateSearchByExtent();
                        if (oldView == this.viewModel.views.rectangle || oldView == this.viewModel.views.point) {
                            topic.publish(VIEWER_GLOBALS.EVENTS.DRAW.USER.DRAW_CANCEL);
                        }
                    }
                    else {
                        if (oldView == this.viewModel.views.rectangle || oldView == this.viewModel.views.point) {
                            topic.publish(VIEWER_GLOBALS.EVENTS.DRAW.USER.DRAW_CANCEL);
                        }
                    }
                },
                handleAnnotationAddedFromUser: function (annoObj) {
                    //{ id:uuid, type:type, graphic:graphic }
                    var isPointBuffer = false;
                    if (this.viewModel.currentView() == this.viewModel.views.point) {
                        //perform a buffer if it exists. the buffer will be the displayed graphic
                        var bufferValue = this.pointDrawBufferValue.get("value");
                        if (!isNaN(bufferValue) && bufferValue > 0) {
                            var bufferUnits = this.viewModel.selectedPointUnits();
                            var distanceAndUnits = {distance: bufferValue, units: bufferUnits};
                            var callback = lang.hitch(this, this.handlePointBufferResponse, annoObj);
                            var errback = lang.hitch(this, this.handlePointBufferError, annoObj);
                            topic.publish(VIEWER_GLOBALS.EVENTS.GEOMETRY_SERVICE.BUFFER_POINT, annoObj.graphic.geometry, distanceAndUnits, callback, errback);
                            isPointBuffer = true;
                        }
                    }
                    this.viewModel.currentView(this.viewModel.views.none);
                    if (!isPointBuffer) {
                        //perform the search right away since we don't have to send another server request for buffering a point
                        this.performSearch(annoObj.graphic);
                    }
                },
                handlePointBufferError: function (annoObj) {
                    this.performSearch(annoObj.graphic);
                },
                handlePointBufferResponse: function (annoObj, bufferResponse) {
                    //clear the X graphic for the point
                    if (bufferResponse != null && lang.isArray(bufferResponse) && bufferResponse.length > 0) {
                        this.performSearch(bufferResponse[0]);
                    }
                    else {
                        this.performSearch(annoObj.graphic);
                    }
                },
                setDraw: function (type) {
                    //clear the last annotation
                    this.clearVisibileGraphics();
                    this.inherited(arguments);
                },
                createUploadView: function () {
                    //set the max upload geometries allowed
                    if (this.geometryUploadWidget == null) {
                        this.geometryUploadWidget = new GeometryUploadWidget();
                        this.geometryUploadWidget.placeAt(this.geometryUploadWidgetContainer);
                        this.geometryUploadWidget.on("performSearch", this.performSearchCallback);
                    }
                },
                createBoundsView: function () {
                    if (this.searchByBoundsWidget == null) {
                        this.searchByBoundsWidget = new SearchByBoundsWidget();
                        this.searchByBoundsWidget.placeAt(this.imageDiscoverySearchByBoundsContainer);
                        this.searchByBoundsWidget.on("boundsGeometryCreated", this.performSearchCallback);
                    }
                },
                clearDraw: function () {
                    this.inherited(arguments);
                    //get zoom back for shift key
                    topic.publish(VIEWER_GLOBALS.EVENTS.DRAW.USER.DRAW_CANCEL);
                }
            });
    });<commit_msg>added array geom check to discoveryWidget<commit_after>define([
    "dojo/_base/declare",
    "dojo/text!./template/ImageDiscoveryTemplate.html",
    "xstyle/css!./theme/ImageDiscoveryTheme.css",
    "dojo/topic",
    "dojo/has",
    'dijit/layout/ContentPane',
    "dojo/_base/lang",
    "dojo/dom-style",
    "dojo/dom-class",
    "esriviewer/ui/base/UITemplatedWidget",
    "esriviewer/ui/draw/base/MapDrawSupport",
    "dojo/_base/Color",
    "../discover/upload/GeometryUploadWidget",
    "./SearchByBoundsWidget",
    "../query/ImageQueryWidget",
    "./model/ImageDiscoveryViewModel",
    "dijit/form/NumberTextBox",
    "esri/symbols/SimpleFillSymbol",
    "esri/symbols/SimpleMarkerSymbol",
    "esri/symbols/SimpleLineSymbol",
    "esri/graphic",
    "esri/geometry/Geometry",
    "esri/geometry/Point",
    "esri/geometry/Polygon",
    "esri/geometry/Extent",
    "../../base/ImageQueryLayerControllerQueryParameters"
],
    function (declare, template, theme, topic, has, ContentPane, lang, domStyle, domClass, UITemplatedWidget, MapDrawSupport, Color, GeometryUploadWidget, SearchByBoundsWidget, ImageQueryWidget, ImageDiscoveryViewModel, NumberTextBox, SimpleFillSymbol, SimpleMarkerSymbol, SimpleLineSymbol, Graphic, Geometry, Point, Polygon, Extent, ImageQueryLayerControllerQueryParameters) {
        return declare(
            [ContentPane, UITemplatedWidget, MapDrawSupport],
            {
                createQueryFieldsDiscoveryContent: false,
                title: "Discover",
                templateString: template,
                constructor: function (params) {
                    lang.mixin(this, params || {});
                    this.currentAddedGraphics = [];
                },
                postCreate: function () {
                    this.inherited(arguments);
                    this.searchByGeometryGeometryQueryErrorback = lang.hitch(this, this.handleSearchByGeometryGeometryQueryError);
                    this.performSearchCallback = lang.hitch(this, this.performSearch);
                    this.viewModel = new ImageDiscoveryViewModel();
                    this.viewModel.on("firstBoundsDisplay", lang.hitch(this, this.createBoundsView));
                    this.viewModel.on("viewChange", lang.hitch(this, this.handleViewChanged));
                    this.viewModel.discoverByFieldsExpanded.subscribe(lang.hitch(this, this.handleDiscoveryByFieldsToggle));
                    this.initSymbology();
                    if (this.createQueryFieldsDiscoveryContent) {
                        this.viewModel.selectedDiscoveryService.subscribe(lang.hitch(this, this.handleSearchServiceChanged));
                    }
                    ko.applyBindings(this.viewModel, this.domNode);
                    if (this.discoverGeometryUploadTaskConfiguration == null || !lang.isObject(this.discoverGeometryUploadTaskConfiguration)) {
                        this.viewModel.searchByGeometryButtonVisible(false);

                    }
                    else {
                        this.createUploadView();
                    }
                    if (this.createQueryFieldsDiscoveryContent) {
                        this.createQueryView();
                    }
                },
                handleDiscoveryByFieldsToggle: function (expanded) {
                    //toggle the view for searching by field value in the discovery widget
                    if (!expanded && this.imageQueryWidget) {
                        this.imageQueryWidget.closePopups();
                    }
                },
                initListeners: function () {
                    //listen for when the accordion has been hiden
                    topic.subscribe(VIEWER_GLOBALS.EVENTS.TOOLS.ACCORDION.HIDE_COMPLETE, lang.hitch(this, this.handleAccordionHidden));
                    //listen for when all query layer controllers have been loaded
                    topic.subscribe(IMAGERY_GLOBALS.EVENTS.QUERY.LAYER_CONTROLLERS.LOADED, lang.hitch(this, this.handleQueryLayerControllersLoaded));
                    this.on("annotationCreated", lang.hitch(this, this.handleAnnotationAddedFromUser));
                    this.on("show", lang.hitch(this, this.handleOnShow));
                    //listen for clear results
                    topic.subscribe(IMAGERY_GLOBALS.EVENTS.QUERY.RESULT.CLEAR, lang.hitch(this, this.handleResultsCleared));
                },
                handleSearchServiceChanged: function (queryController) {
                    //when search service changed the unique values need to be reloaded
                    if (this.imageQueryWidget) {
                        if (queryController == null) {
                            this.hideUniqueValuesContent();
                        }
                        else {
                            this.viewModel.discoverByFieldsHeaderVisible(true);
                            this.imageQueryWidget.setCurrentQueryLayerController(queryController)
                        }
                    }
                },
                handleQueryLayerControllersLoaded: function (queryLayerControllers) {
                    var currentQueryLayerController;
                    var currentQueryLayer;
                    this.queryLayerControllers = queryLayerControllers;
                    if (queryLayerControllers.length == 1) {
                        this.viewModel.selectSearchServiceVisible(false);
                        if (this.createQueryFieldsDiscoveryContent) {
                            this.viewModel.discoverByFieldsHeaderVisible(true);
                            this.handleSearchServiceChanged(queryLayerControllers[0]);
                        }
                    }
                    else {
                        this.viewModel.selectSearchServiceVisible(true);
                        for (var i = 0; i < queryLayerControllers.length; i++) {
                            currentQueryLayerController = queryLayerControllers[i];
                            currentQueryLayer = (currentQueryLayerController && currentQueryLayerController.layer) ? currentQueryLayerController.layer : null;
                            if (currentQueryLayerController && currentQueryLayer) {
                                this.viewModel.discoveryServicesList.push({label: currentQueryLayer.searchServiceLabel, value: currentQueryLayerController});
                            }
                        }
                    }
                },
                hideUniqueValuesContent: function () {
                    //hide unique values view
                    this.viewModel.discoverByFieldsExpanded(false);
                    this.viewModel.discoverByFieldsHeaderVisible(false);
                },
                createQueryView: function () {
                    //create the view which shows unique values for the active service
                    this.imageQueryWidget = new ImageQueryWidget();
                    this.imageQueryWidget.on("noUniqueValuesReturned", lang.hitch(this, this.hideUniqueValuesContent));
                    this.imageQueryWidget.placeAt(this.imageDiscoveryByQueryContainer);
                },
                loadViewerConfigurationData: function () {
                    //load the configuration
                    var discoveryGeometryUploadConfiguration;
                    topic.publish(IMAGERY_GLOBALS.EVENTS.CONFIGURATION.GET_ENTRY, "discoverGeometryUploadTask", function (discoveryGeometryUploadConf) {
                        discoveryGeometryUploadConfiguration = discoveryGeometryUploadConf;
                    });
                    if (discoveryGeometryUploadConfiguration != null && lang.isObject(discoveryGeometryUploadConfiguration)) {
                        this.discoverGeometryUploadTaskConfiguration = discoveryGeometryUploadConfiguration;
                    }
                    var discoveryQueryFields;
                    topic.publish(IMAGERY_GLOBALS.EVENTS.CONFIGURATION.GET_ENTRY, "imageDiscoveryQueryFields", function (discoveryQueryFieldsConf) {
                        discoveryQueryFields = discoveryQueryFieldsConf;
                    });
                    if (discoveryQueryFields != null && lang.isArray(discoveryQueryFields) && discoveryQueryFields.length > 0) {
                        this.createQueryFieldsDiscoveryContent = !(has("ie") == 7);
                    }
                },
                handleSearchByGeometryGeometryQueryError: function (msg) {
                    this.clearDraw();
                },
                initSymbology: function () {
                    //init the discovery widget symbology
                    this.polygonSymbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
                            new Color([0, 0, 255]), 1), new Color([0, 0, 255, 0]));

                    this.pointSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_X, 1,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
                            new Color("blue")));

                    this.envelopeSymbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID,
                        new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
                            new Color([0, 0, 255]), 1),
                        new Color([0, 0, 0, 0]));
                },
                handleAccordionHidden: function () {
                    if (this.imageQueryWidget) {
                        this.imageQueryWidget.closePopups();

                    }
                },
                handleOnShow: function () {
                    //fire event telling other widgets the discovery widget has come into view
                    topic.publish(IMAGERY_GLOBALS.EVENTS.DISCOVERY.ON_SHOW);
                },
                handleResultsCleared: function () {
                    //when results are cleared remove and geometries left over from the initial search
                    this.clearVisibileGraphics();
                },
                clearVisibileGraphics: function () {
                    //clears any graphics on the map created from the discovery widget
                    if (this.currentAddedGraphics) {
                        for (var i = 0; i < this.currentAddedGraphics.length; i++) {
                            topic.publish(VIEWER_GLOBALS.EVENTS.MAP.GRAPHICS.REMOVE, this.currentAddedGraphics[i]);

                        }
                    }
                    this.currentAddedGraphics = [];
                },
                activateSearchByExtent: function () {
                    //searches by map extent
                    var mapExtent = null;
                    topic.publish(VIEWER_GLOBALS.EVENTS.MAP.EXTENT.GET_EXTENT, function (ext) {
                        mapExtent = ext;
                    });
                    if (mapExtent == null) {
                        return;
                    }
                    this.performSearch(mapExtent, false);
                },
                performSearch: function (searchObject, zoomToArea) {
                    //figure out what type of search is being performed and perform the search
                    if (searchObject == null) {
                        return;
                    }
                    //searchObject can either be a graphic,geometry or array of geometries
                    var graphic;
                    var whereClause = "";
                    if (this.imageQueryWidget != null && this.viewModel.discoverByFieldsExpanded()) {
                        whereClause = this.imageQueryWidget.getQuery();
                    }

                    //clear the previous result
                    topic.publish(IMAGERY_GLOBALS.EVENTS.QUERY.RESULT.CLEAR);
                    //get the services to query
                    var queryLayerControllers;
                    var selectedDiscoveryService = this.viewModel.selectedDiscoveryService();
                    if (selectedDiscoveryService) {
                        queryLayerControllers = [selectedDiscoveryService];
                    }
                    else {
                        queryLayerControllers = this.queryLayerControllers;
                    }
                    var imageQueryParameters = new ImageQueryLayerControllerQueryParameters({
                        queryLayerControllers: queryLayerControllers,
                        whereClause: whereClause,
                        returnGeometry: true
                    });
                    var searchGraphic;
                    if (lang.isArray(searchObject) && searchObject.length > 0) {
                        //just take the first entry, should be a multipart polygon
                        searchObject = searchObject[0];
                    }
                    //figure out if the search object is already a graphic or if it is a geometry that needs to be turned into a graphic
                    if (searchObject instanceof Graphic) {
                        searchGraphic = searchObject;
                        this.currentAddedGraphics.push(searchObject);
                    }
                    else if (searchObject instanceof Geometry) {
                        graphic = null;
                        if (searchObject instanceof Point) {
                            graphic = new Graphic(searchObject, this.pointSymbol);
                        }
                        else if (searchObject instanceof Polygon) {
                            graphic = new Graphic(searchObject, this.polygonSymbol);
                        }
                        else if (searchObject instanceof Extent) {
                            graphic = new Graphic(searchObject, this.polygonSymbol);
                        }
                        if (graphic) {
                            this.currentAddedGraphics.push(graphic);
                            //add the graphic to the map
                            topic.publish(VIEWER_GLOBALS.EVENTS.MAP.GRAPHICS.ADD, graphic);
                            searchGraphic = graphic;
                        }

                    }
                    imageQueryParameters.geometry = searchGraphic.geometry;
                    imageQueryParameters.errback = this.searchByGeometryGeometryQueryErrorback;
                    topic.publish(IMAGERY_GLOBALS.EVENTS.QUERY.SEARCH.GEOMETRY, imageQueryParameters);
                },
                handleViewChanged: function (oldView, newView) {
                    //figure out what view we are in and publish draw events accordingly
                    if (oldView == newView && newView != this.viewModel.views.extent) {
                        return;
                    }
                    if (newView == this.viewModel.views.point) {
                        this.setDraw(VIEWER_GLOBALS.EVENTS.MAP.TOOLS.DRAW_POINT);
                    }
                    else if (newView == this.viewModel.views.rectangle) {
                        this.setDraw(VIEWER_GLOBALS.EVENTS.MAP.TOOLS.DRAW_RECTANGLE);

                    }
                    else if (newView == this.viewModel.views.extent) {
                        this.activateSearchByExtent();
                        if (oldView == this.viewModel.views.rectangle || oldView == this.viewModel.views.point) {
                            topic.publish(VIEWER_GLOBALS.EVENTS.DRAW.USER.DRAW_CANCEL);
                        }
                    }
                    else {
                        if (oldView == this.viewModel.views.rectangle || oldView == this.viewModel.views.point) {
                            topic.publish(VIEWER_GLOBALS.EVENTS.DRAW.USER.DRAW_CANCEL);
                        }
                    }
                },
                handleAnnotationAddedFromUser: function (annoObj) {
                    //{ id:uuid, type:type, graphic:graphic }
                    var isPointBuffer = false;
                    if (this.viewModel.currentView() == this.viewModel.views.point) {
                        //perform a buffer if it exists. the buffer will be the displayed graphic
                        var bufferValue = this.pointDrawBufferValue.get("value");
                        if (!isNaN(bufferValue) && bufferValue > 0) {
                            var bufferUnits = this.viewModel.selectedPointUnits();
                            var distanceAndUnits = {distance: bufferValue, units: bufferUnits};
                            var callback = lang.hitch(this, this.handlePointBufferResponse, annoObj);
                            var errback = lang.hitch(this, this.handlePointBufferError, annoObj);
                            topic.publish(VIEWER_GLOBALS.EVENTS.GEOMETRY_SERVICE.BUFFER_POINT, annoObj.graphic.geometry, distanceAndUnits, callback, errback);
                            isPointBuffer = true;
                        }
                    }
                    this.viewModel.currentView(this.viewModel.views.none);
                    if (!isPointBuffer) {
                        //perform the search right away since we don't have to send another server request for buffering a point
                        this.performSearch(annoObj.graphic);
                    }
                },
                handlePointBufferError: function (annoObj) {
                    this.performSearch(annoObj.graphic);
                },
                handlePointBufferResponse: function (annoObj, bufferResponse) {
                    //clear the X graphic for the point
                    if (bufferResponse != null && lang.isArray(bufferResponse) && bufferResponse.length > 0) {
                        this.performSearch(bufferResponse[0]);
                    }
                    else {
                        this.performSearch(annoObj.graphic);
                    }
                },
                setDraw: function (type) {
                    //clear the last annotation
                    this.clearVisibileGraphics();
                    this.inherited(arguments);
                },
                createUploadView: function () {
                    //set the max upload geometries allowed
                    if (this.geometryUploadWidget == null) {
                        this.geometryUploadWidget = new GeometryUploadWidget();
                        this.geometryUploadWidget.placeAt(this.geometryUploadWidgetContainer);
                        this.geometryUploadWidget.on("performSearch", this.performSearchCallback);
                    }
                },
                createBoundsView: function () {
                    if (this.searchByBoundsWidget == null) {
                        this.searchByBoundsWidget = new SearchByBoundsWidget();
                        this.searchByBoundsWidget.placeAt(this.imageDiscoverySearchByBoundsContainer);
                        this.searchByBoundsWidget.on("boundsGeometryCreated", this.performSearchCallback);
                    }
                },
                clearDraw: function () {
                    this.inherited(arguments);
                    //get zoom back for shift key
                    topic.publish(VIEWER_GLOBALS.EVENTS.DRAW.USER.DRAW_CANCEL);
                }
            });
    });<|endoftext|>


<commit_before>// URL: https://beta.observablehq.com/@randomfractals/chicago-crimes-by-day
// Title: Chicago Crimes by Day
// Author: Taras Novak (@randomfractals)
// Version: 389
// Runtime version: 1

const m0 = {
  id: "e901da8a28f3f554@389",
  variables: [
    {
      inputs: ["md"],
      value: (function(md){return(
md`# Chicago Crimes by Day

This chart shows daily Chicago crimes for 6 months of 2018.

*UX tip: mouse over to see the number of reported crimes per day*`
)})
    },
    {
      name: "viewof weekday",
      inputs: ["html"],
      value: (function(html){return(
html`<select>
  <option value=sunday>Sunday-based weeks
  <option value=monday>Monday-based weeks
  <option value=weekday>Weekdays only
</select>`
)})
    },
    {
      name: "weekday",
      inputs: ["Generators","viewof weekday"],
      value: (G, _) => G.input(_)
    },
    {
      name: "chart",
      inputs: ["d3","data","DOM","width","height","cellSize","weekday","countDay","formatDay","timeWeek","color","formatDate","pathMonth","formatMonth"],
      value: (function(d3,data,DOM,width,height,cellSize,weekday,countDay,formatDay,timeWeek,color,formatDate,pathMonth,formatMonth)
{
  const years = d3.nest()
      .key(d => d.date.getFullYear())
    .entries(data)
    .reverse();

  const svg = d3.select(DOM.svg(width, height * years.length))
      .style("font", "10px sans-serif")
      .style("width", "100%")
      .style("height", "auto");

  const year = svg.selectAll("g")
    .data(years)
    .enter().append("g")
      .attr("transform", (d, i) => `translate(40,${height * i + cellSize * 1.5})`);

  year.append("text")
      .attr("x", -5)
      .attr("y", -5)
      .attr("font-weight", "bold")
      .attr("text-anchor", "end")
      .text(d => d.key);

  year.append("g")
      .attr("text-anchor", "end")
    .selectAll("text")
    .data((weekday === "weekday" ? d3.range(2, 7) : d3.range(7)).map(i => new Date(1995, 0, i)))
    .enter().append("text")
      .attr("x", -5)
      .attr("y", d => (countDay(d) + 0.5) * cellSize)
      .attr("dy", "0.31em")
      .text(formatDay);

  year.append("g")
    .selectAll("rect")
    .data(d => d.values)
    .enter().append("rect")
      .attr("width", cellSize - 1)
      .attr("height", cellSize - 1)
      .attr("x", d => timeWeek.count(d3.timeYear(d.date), d.date) * cellSize + 0.5)
      .attr("y", d => countDay(d.date) * cellSize + 0.5)
      .attr("fill", d => color(d.value))
    .append("title")
      .text(d => `${formatDate(d.date)}: ${d.value.toLocaleString()}`);

  const month = year.append("g")
    .selectAll("g")
    .data(d => d3.timeMonths(d3.timeMonth(d.values[0].date), d.values[d.values.length - 1].date))
    .enter().append("g");

  month.filter((d, i) => i).append("path")
      .attr("fill", "none")
      .attr("stroke", "#fff")
      .attr("stroke-width", 3)
      .attr("d", pathMonth);

  month.append("text")
      .attr("x", d => timeWeek.count(d3.timeYear(d), timeWeek.ceil(d)) * cellSize + 2)
      .attr("y", -5)
      .text(formatMonth);

  return svg.node();
}
)
    },
    {
      name: "cellSize",
      value: (function(){return(
17
)})
    },
    {
      name: "width",
      value: (function(){return(
964
)})
    },
    {
      name: "height",
      inputs: ["cellSize","weekday"],
      value: (function(cellSize,weekday){return(
cellSize * (weekday === "weekday" ? 7 : 9)
)})
    },
    {
      name: "timeWeek",
      inputs: ["weekday","d3"],
      value: (function(weekday,d3){return(
weekday === "sunday" ? d3.timeSunday : d3.timeMonday
)})
    },
    {
      name: "countDay",
      inputs: ["weekday"],
      value: (function(weekday){return(
weekday === "sunday" ? d => d.getDay() : d => (d.getDay() + 6) % 7
)})
    },
    {
      name: "pathMonth",
      inputs: ["weekday","countDay","timeWeek","d3","cellSize"],
      value: (function(weekday,countDay,timeWeek,d3,cellSize){return(
function pathMonth(t) {
  const n = weekday === "weekday" ? 5 : 7;
  const d = Math.max(0, Math.min(n, countDay(t)));
  const w = timeWeek.count(d3.timeYear(t), t);
  return `${d === 0 ? `M${w * cellSize},0`
      : d === n ? `M${(w + 1) * cellSize},0`
      : `M${(w + 1) * cellSize},0V${d * cellSize}H${w * cellSize}`}V${n * cellSize}`;
}
)})
    },
    {
      name: "formatDate",
      inputs: ["d3"],
      value: (function(d3){return(
d3.timeFormat("%x")
)})
    },
    {
      name: "formatDay",
      value: (function(){return(
d => "SMTWTFS"[d.getDay()]
)})
    },
    {
      name: "formatMonth",
      inputs: ["d3"],
      value: (function(d3){return(
d3.timeFormat("%b")
)})
    },
    {
      name: "color",
      inputs: ["d3","data"],
      value: (function(d3,data){return(
d3.scaleSequential(d3.interpolateYlOrRd).domain([d3.min(data, d => d.value), d3.max(data, d => d.value)])
)})
    },
    {
      name: "data",
      inputs: ["dailyCounts"],
      value: (function(dailyCounts){return(
dailyCounts
)})
    },
    {
      name: "d3",
      inputs: ["require"],
      value: (function(require){return(
require("https://d3js.org/d3.v5.min.js")
)})
    },
    {
      inputs: ["md"],
      value: (function(md){return(
md `## Crime Data`
)})
    },
    {
      name: "dataUrl",
      value: (function(){return(
'https://raw.githubusercontent.com/RandomFractals/ChicagoCrimes/master/data/2018/chicago-crimes-2018.arrow'
)})
    },
    {
      name: "dataTable",
      inputs: ["loadData","dataUrl","arrow"],
      value: (function(loadData,dataUrl,arrow){return(
loadData(dataUrl).then(buffer => arrow.Table.from(new Uint8Array(buffer)))
)})
    },
    {
      name: "dailyData",
      inputs: ["groupByDay","dataTable"],
      value: (function(groupByDay,dataTable){return(
groupByDay(dataTable)
)})
    },
    {
      name: "dailyCounts",
      inputs: ["dailyData","timezoneOffset"],
      value: (function(dailyData,timezoneOffset){return(
Object.keys(dailyData)
  .map(day => {
    return {date: new Date(new Date(day).getTime() + timezoneOffset), value: dailyData[day].length};
  })
)})
    },
    {
      name: "timezoneOffset",
      value: (function(){return(
6*60*60*1000
)})
    },
    {
      name: "groupByDay",
      inputs: ["arrow","toDate"],
      value: (function(arrow,toDate){return(
function groupByDay(data) {
  let groupData, date, location, arrested, info, results = {};
  const dateFilter = arrow.predicate.custom(i => {
    const date = toDate(data.getColumn('Date').get(i));
    return (date.getMonth() <= 6); // through June
  }, b => 1);
  data.filter(dateFilter)
  .scan((index) => {
    const day = toDate(date(index)).toISOString().substring(0, 10); // ISO date string
    const groupArray = results[day];
    if (!groupArray) {
      results[day] = [];
    }
    const dataRecord = {};
    dataRecord['date'] = toDate(date(index));
    dataRecord['location'] = location(index);
    dataRecord['arrested'] = arrested(index);
    dataRecord['info'] = info(index);
    results[day].push(dataRecord);
  }, (batch) => {
    date = arrow.predicate.col('Date').bind(batch);
    location = arrow.predicate.col('LocationDescription').bind(batch);
    arrested = arrow.predicate.col('Arrest').bind(batch);
    info = arrow.predicate.col('Description').bind(batch);
  });
  return results;
}
)})
    },
    {
      from: "@randomfractals/apache-arrow",
      name: "loadData",
      remote: "loadData"
    },
    {
      from: "@randomfractals/apache-arrow",
      name: "toDate",
      remote: "toDate"
    },
    {
      name: "arrow",
      inputs: ["require"],
      value: (function(require){return(
require('apache-arrow')
)})
    }
  ]
};

const m1 = {
  id: "@randomfractals/apache-arrow",
  variables: [
    {
      name: "loadData",
      value: (function(){return(
async function loadData(dataUrl){
  const response = await fetch(dataUrl);
  return await response.arrayBuffer();
}
)})
    },
    {
      name: "toDate",
      value: (function(){return(
function toDate(timestamp) {
  // Appache Arrow Timestamp is a 64-bit int of milliseconds since the epoch,
  // represented as two 32-bit ints in JS to preserve precision.
  // The fist number is the "low" int and the second number is the "high" int.
  return new Date((timestamp[1] * Math.pow(2, 32) + timestamp[0])/1000);
}
)})
    }
  ]
};

const notebook = {
  id: "e901da8a28f3f554@389",
  modules: [m0,m1]
};

export default notebook;
<commit_msg>intro + date transform and tip formatting changes<commit_after>// URL: https://beta.observablehq.com/@randomfractals/chicago-crimes-by-day
// Title: Chicago Crimes by Day
// Author: Taras Novak (@randomfractals)
// Version: 407
// Runtime version: 1

const m0 = {
  id: "e901da8a28f3f554@407",
  variables: [
    {
      inputs: ["md"],
      value: (function(md){return(
md`# Chicago Crimes by Day

*mouseover to see the number of reported crimes per day*`
)})
    },
    {
      name: "viewof weekday",
      inputs: ["html"],
      value: (function(html){return(
html`<select>
  <option value=monday>Monday-based weeks
  <option value=sunday>Sunday-based weeks
  <option value=weekday>Weekdays only
</select>`
)})
    },
    {
      name: "weekday",
      inputs: ["Generators","viewof weekday"],
      value: (G, _) => G.input(_)
    },
    {
      name: "chart",
      inputs: ["d3","data","DOM","width","height","cellSize","weekday","countDay","formatDay","timeWeek","color","formatDate","pathMonth","formatMonth"],
      value: (function(d3,data,DOM,width,height,cellSize,weekday,countDay,formatDay,timeWeek,color,formatDate,pathMonth,formatMonth)
{
  const years = d3.nest()
      .key(d => d.date.getFullYear())
    .entries(data)
    .reverse();

  const svg = d3.select(DOM.svg(width, height * years.length))
      .style("font", "10px sans-serif")
      .style("width", "100%")
      .style("height", "auto");

  const year = svg.selectAll("g")
    .data(years)
    .enter().append("g")
      .attr("transform", (d, i) => `translate(40,${height * i + cellSize * 1.5})`);

  year.append("text")
      .attr("x", -5)
      .attr("y", -5)
      .attr("font-weight", "bold")
      .attr("text-anchor", "end")
      .text(d => d.key);

  year.append("g")
      .attr("text-anchor", "end")
    .selectAll("text")
    .data((weekday === "weekday" ? d3.range(2, 7) : d3.range(7)).map(i => new Date(1995, 0, i)))
    .enter().append("text")
      .attr("x", -5)
      .attr("y", d => (countDay(d) + 0.5) * cellSize)
      .attr("dy", "0.31em")
      .text(formatDay);

  year.append("g")
    .selectAll("rect")
    .data(d => d.values)
    .enter().append("rect")
      .attr("width", cellSize - 1)
      .attr("height", cellSize - 1)
      .attr("x", d => timeWeek.count(d3.timeYear(d.date), d.date) * cellSize + 0.5)
      .attr("y", d => countDay(d.date) * cellSize + 0.5)
      .attr("fill", d => color(d.value))
    .append("title")
      .text(d => `${d.value.toLocaleString()} on ${formatDate(d.date)}`);

  const month = year.append("g")
    .selectAll("g")
    .data(d => d3.timeMonths(d3.timeMonth(d.values[0].date), d.values[d.values.length - 1].date))
    .enter().append("g");

  month.filter((d, i) => i).append("path")
      .attr("fill", "none")
      .attr("stroke", "#fff")
      .attr("stroke-width", 3)
      .attr("d", pathMonth);

  month.append("text")
      .attr("x", d => timeWeek.count(d3.timeYear(d), timeWeek.ceil(d)) * cellSize + 2)
      .attr("y", -5)
      .text(formatMonth);

  return svg.node();
}
)
    },
    {
      name: "cellSize",
      value: (function(){return(
17
)})
    },
    {
      name: "width",
      value: (function(){return(
964
)})
    },
    {
      name: "height",
      inputs: ["cellSize","weekday"],
      value: (function(cellSize,weekday){return(
cellSize * (weekday === "weekday" ? 7 : 9)
)})
    },
    {
      name: "timeWeek",
      inputs: ["weekday","d3"],
      value: (function(weekday,d3){return(
weekday === "sunday" ? d3.timeSunday : d3.timeMonday
)})
    },
    {
      name: "countDay",
      inputs: ["weekday"],
      value: (function(weekday){return(
weekday === "sunday" ? d => d.getDay() : d => (d.getDay() + 6) % 7
)})
    },
    {
      name: "pathMonth",
      inputs: ["weekday","countDay","timeWeek","d3","cellSize"],
      value: (function(weekday,countDay,timeWeek,d3,cellSize){return(
function pathMonth(t) {
  const n = weekday === "weekday" ? 5 : 7;
  const d = Math.max(0, Math.min(n, countDay(t)));
  const w = timeWeek.count(d3.timeYear(t), t);
  return `${d === 0 ? `M${w * cellSize},0`
      : d === n ? `M${(w + 1) * cellSize},0`
      : `M${(w + 1) * cellSize},0V${d * cellSize}H${w * cellSize}`}V${n * cellSize}`;
}
)})
    },
    {
      name: "formatDate",
      inputs: ["d3"],
      value: (function(d3){return(
d3.timeFormat('%A, %B %e')
)})
    },
    {
      name: "formatDay",
      value: (function(){return(
d => "SMTWTFS"[d.getDay()]
)})
    },
    {
      name: "formatMonth",
      inputs: ["d3"],
      value: (function(d3){return(
d3.timeFormat("%b")
)})
    },
    {
      name: "color",
      inputs: ["d3","data"],
      value: (function(d3,data){return(
d3.scaleSequential(d3.interpolateYlOrRd).domain([d3.min(data, d => d.value), d3.max(data, d => d.value)])
)})
    },
    {
      name: "data",
      inputs: ["dailyCounts"],
      value: (function(dailyCounts){return(
dailyCounts
)})
    },
    {
      name: "d3",
      inputs: ["require"],
      value: (function(require){return(
require("https://d3js.org/d3.v5.min.js")
)})
    },
    {
      inputs: ["md"],
      value: (function(md){return(
md `## Crime Data`
)})
    },
    {
      name: "dataUrl",
      value: (function(){return(
'https://raw.githubusercontent.com/RandomFractals/ChicagoCrimes/master/data/2018/chicago-crimes-2018.arrow'
)})
    },
    {
      name: "dataTable",
      inputs: ["loadData","dataUrl","arrow"],
      value: (function(loadData,dataUrl,arrow){return(
loadData(dataUrl).then(buffer => arrow.Table.from(new Uint8Array(buffer)))
)})
    },
    {
      name: "dailyData",
      inputs: ["groupByDay","dataTable"],
      value: (function(groupByDay,dataTable){return(
groupByDay(dataTable)
)})
    },
    {
      name: "dailyCounts",
      inputs: ["dailyData","timezoneOffset"],
      value: (function(dailyData,timezoneOffset){return(
Object.keys(dailyData)
  .map(day => {
    return {date: new Date(new Date(day).getTime() + timezoneOffset), value: dailyData[day].length};
  })
)})
    },
    {
      name: "timezoneOffset",
      value: (function(){return(
(new Date().getTimezoneOffset() + 60) * 60 * 1000
)})
    },
    {
      name: "groupByDay",
      inputs: ["arrow","toDate"],
      value: (function(arrow,toDate){return(
function groupByDay(data) {
  let groupData, date, location, arrested, info, results = {};
  const dateFilter = arrow.predicate.custom(i => {
    const date = toDate(data.getColumn('Date').get(i));
    return (date.getMonth() <= 6); // through June
  }, b => 1);
  data.filter(dateFilter)
  .scan((index) => {
    const day = toDate(date(index)).toISOString().substring(0, 10); // ISO date string
    if (!results[day]) {
      results[day] = [];
    }
    const dataRecord = {};
    dataRecord['date'] = toDate(date(index));
    dataRecord['location'] = location(index);
    dataRecord['arrested'] = arrested(index);
    dataRecord['info'] = info(index);
    results[day].push(dataRecord);
  }, (batch) => {
    date = arrow.predicate.col('Date').bind(batch);
    location = arrow.predicate.col('LocationDescription').bind(batch);
    arrested = arrow.predicate.col('Arrest').bind(batch);
    info = arrow.predicate.col('Description').bind(batch);
  });
  return results;
}
)})
    },
    {
      from: "@randomfractals/apache-arrow",
      name: "loadData",
      remote: "loadData"
    },
    {
      from: "@randomfractals/apache-arrow",
      name: "toDate",
      remote: "toDate"
    },
    {
      name: "arrow",
      inputs: ["require"],
      value: (function(require){return(
require('apache-arrow')
)})
    }
  ]
};

const m1 = {
  id: "@randomfractals/apache-arrow",
  variables: [
    {
      name: "loadData",
      value: (function(){return(
async function loadData(dataUrl){
  const response = await fetch(dataUrl);
  return await response.arrayBuffer();
}
)})
    },
    {
      name: "toDate",
      value: (function(){return(
function toDate(timestamp) {
  // Appache Arrow Timestamp is a 64-bit int of milliseconds since the epoch,
  // represented as two 32-bit ints in JS to preserve precision.
  // The fist number is the "low" int and the second number is the "high" int.
  return new Date((timestamp[1] * Math.pow(2, 32) + timestamp[0])/1000);
}
)})
    }
  ]
};

const notebook = {
  id: "e901da8a28f3f554@407",
  modules: [m0,m1]
};

export default notebook;
<|endoftext|>


<commit_before>/**
 * DashboardIdeasWidget component
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import Tab from '@material/react-tab';
import TabBar from '@material/react-tab-bar';
import { useHash, useMount } from 'react-use';
import { useInView } from 'react-intersection-observer';

/**
 * WordPress dependencies
 */
import { __, sprintf } from '@wordpress/i18n';
import {
	createInterpolateElement,
	useState,
	useEffect,
	useCallback,
} from '@wordpress/element';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import {
	MODULES_IDEA_HUB,
	IDEA_HUB_GA_CATEGORY_WIDGET,
} from '../../../datastore/constants';
import { trackEvent } from '../../../../../util';
import whenActive from '../../../../../util/when-active';
import DashboardCTA from '../DashboardCTA';
import EmptyIcon from '../../../../../../svg/zero-state-yellow.svg';
import NewIdeas from './NewIdeas';
import SavedIdeas from './SavedIdeas';
import DraftIdeas from './DraftIdeas';
import Empty from './Empty';
import Footer from './Footer';
const { useSelect } = Data;

function getHash( hash ) {
	return hash ? hash.replace( '#', '' ) : false;
}

function isValidHash( hash ) {
	return getHash( hash ) in DashboardIdeasWidget.tabToIndex;
}

function getIdeaHubContainerOffset( widgetOffset ) {
	const header =
		document.querySelector( '.googlesitekit-header' )?.offsetHeight || 0;
	const adminBar = document.getElementById( 'wpadminbar' )?.offsetHeight || 0;
	const marginBottom = 24;
	const headerOffset = header + adminBar + marginBottom;

	return global.window.pageYOffset + widgetOffset - headerOffset;
}

function DashboardIdeasWidget( props ) {
	const { defaultActiveTabIndex, Widget, WidgetReportError } = props;

	const [ trackedWidgetView, setTrackedWidgetView ] = useState( false );

	const { hasNoIdeas, hasManyIdeas, savedIdeas, draftIdeas } = useSelect(
		( select ) => {
			const newIdeas = select( MODULES_IDEA_HUB ).getNewIdeas();
			const saved = select( MODULES_IDEA_HUB ).getSavedIdeas();
			const draft = select( MODULES_IDEA_HUB ).getDraftPostIdeas();

			let noIdeas, manyIdeas;

			if (
				newIdeas?.length === 0 &&
				saved?.length === 0 &&
				draft?.length === 0
			) {
				noIdeas = true;
			}

			if (
				newIdeas?.length > 0 ||
				saved?.length > 0 ||
				draft?.length > 0
			) {
				manyIdeas = true;
			}

			return {
				hasNoIdeas: noIdeas,
				hasManyIdeas: manyIdeas,
				savedIdeas: saved,
				draftIdeas: draft,
			};
		}
	);

	const [ hash, setHash ] = useHash();
	const [ activeTabIndex, setActiveTabIndex ] = useState(
		DashboardIdeasWidget.tabToIndex[ getHash( hash ) ] ||
			defaultActiveTabIndex
	);
	const activeTab = DashboardIdeasWidget.tabIDsByIndex[ activeTabIndex ];

	const [ ideaHubContainer, inView ] = useInView( {
		triggerOnce: true,
		threshold: 0.25,
	} );

	useEffect( () => {
		if ( inView ) {
			trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'widget_view' );
		}
	}, [ inView ] );

	useEffect( () => {
		// Do nothing if the following events have already been tracked
		// or the widget hasn't appeared in the viewport yet.
		if ( trackedWidgetView || ! inView ) {
			return;
		}

		if ( hasNoIdeas ) {
			trackEvent(
				IDEA_HUB_GA_CATEGORY_WIDGET,
				'widget_gathering_data_view'
			);
		} else if ( hasManyIdeas ) {
			trackEvent(
				IDEA_HUB_GA_CATEGORY_WIDGET,
				'default_tab_view',
				DashboardIdeasWidget.tabIDsByIndex[ activeTabIndex ]
			);
		}

		if ( hasNoIdeas || hasManyIdeas ) {
			setTrackedWidgetView( true );
		}
	}, [
		hasNoIdeas,
		hasManyIdeas,
		trackedWidgetView,
		setTrackedWidgetView,
		activeTabIndex,
		inView,
	] );

	useMount( () => {
		if ( ! ideaHubContainer?.current || ! isValidHash( hash ) ) {
			return;
		}

		setTimeout( () => {
			global.window.scrollTo( {
				top: getIdeaHubContainerOffset(
					ideaHubContainer.current.getBoundingClientRect().top
				),
				behavior: 'smooth',
			} );
		}, 1000 );
	} );

	const handleTabUpdate = useCallback(
		( tabIndex ) => {
			const slug = DashboardIdeasWidget.tabIDsByIndex[ tabIndex ];

			setActiveTabIndex( tabIndex );
			setHash( slug );

			trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'tab_select', slug );
		},
		[ setHash, setActiveTabIndex ]
	);

	if ( hasNoIdeas ) {
		return (
			<Widget noPadding>

					<Empty
						Icon={ <EmptyIcon /> }
						title={ __(
							'Idea Hub is generating ideas',
							'google-site-kit'
						) }
						subtitle={ __(
							'This could take 24 hours.',
							'google-site-kit'
						) }
					/>

			</Widget>
		);
	}

	const WrappedFooter = () => (

	);

	return (
		<Widget noPadding Footer={ WrappedFooter }>

						{ __(
							'Ideas to write about based on unanswered searches',
							'google-site-kit'
						) }

					<TabBar
						activeIndex={ activeTabIndex }
						handleActiveIndexUpdate={ handleTabUpdate }
						className="googlesitekit-idea-hub__tabs"
					>
						<Tab focusOnActivate={ false }>
							{ __( 'New', 'google-site-kit' ) }
						</Tab>
						<Tab focusOnActivate={ false }>
							{ savedIdeas?.length >= 0 &&
								createInterpolateElement(
									sprintf(
										/* translators: %s: number of saved Idea Hub ideas */
										__(
											'Saved (%s)',
											'google-site-kit'
										),
										savedIdeas.length
									),
									{
										span: ,
									}
								) }
							{ savedIdeas?.length === undefined &&
								__( 'Saved', 'google-site-kit' ) }
						</Tab>
						<Tab focusOnActivate={ false }>
							{ draftIdeas?.length >= 0 &&
								createInterpolateElement(
									sprintf(
										/* translators: %s: number of draft Idea Hub ideas */
										__(
											'Drafts (%s)',
											'google-site-kit'
										),
										draftIdeas.length
									),
									{
										span: ,
									}
								) }
							{ draftIdeas?.length === undefined &&
								__( 'Drafts', 'google-site-kit' ) }
						</Tab>
					</TabBar>

						<NewIdeas WidgetReportError={ WidgetReportError } />

						<SavedIdeas WidgetReportError={ WidgetReportError } />

						<DraftIdeas WidgetReportError={ WidgetReportError } />

		</Widget>
	);
}

DashboardIdeasWidget.tabToIndex = {
	'new-ideas': 0,
	'saved-ideas': 1,
	'draft-ideas': 2,
};

DashboardIdeasWidget.tabIDsByIndex = Object.keys(
	DashboardIdeasWidget.tabToIndex
);

DashboardIdeasWidget.propTypes = {
	Widget: PropTypes.elementType.isRequired,
	defaultActiveTabIndex: PropTypes.number,
};

DashboardIdeasWidget.defaultProps = {
	defaultActiveTabIndex: 0,
};

export default whenActive( {
	moduleName: 'idea-hub',
	FallbackComponent: DashboardCTA,
} )( DashboardIdeasWidget );
<commit_msg>Address code review feedback.<commit_after>/**
 * DashboardIdeasWidget component
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import Tab from '@material/react-tab';
import TabBar from '@material/react-tab-bar';
import { useHash, useMount } from 'react-use';
import { useInView } from 'react-intersection-observer';

/**
 * WordPress dependencies
 */
import { __, sprintf } from '@wordpress/i18n';
import {
	createInterpolateElement,
	useState,
	useEffect,
	useCallback,
} from '@wordpress/element';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import {
	MODULES_IDEA_HUB,
	IDEA_HUB_GA_CATEGORY_WIDGET,
} from '../../../datastore/constants';
import { trackEvent } from '../../../../../util';
import whenActive from '../../../../../util/when-active';
import DashboardCTA from '../DashboardCTA';
import EmptyIcon from '../../../../../../svg/zero-state-yellow.svg';
import NewIdeas from './NewIdeas';
import SavedIdeas from './SavedIdeas';
import DraftIdeas from './DraftIdeas';
import Empty from './Empty';
import Footer from './Footer';
const { useSelect } = Data;

function getHash( hash ) {
	return hash ? hash.replace( '#', '' ) : false;
}

function isValidHash( hash ) {
	return getHash( hash ) in DashboardIdeasWidget.tabToIndex;
}

function getIdeaHubContainerOffset( widgetOffset ) {
	const header =
		document.querySelector( '.googlesitekit-header' )?.offsetHeight || 0;
	const adminBar = document.getElementById( 'wpadminbar' )?.offsetHeight || 0;
	const marginBottom = 24;
	const headerOffset = header + adminBar + marginBottom;

	return global.window.pageYOffset + widgetOffset - headerOffset;
}

function DashboardIdeasWidget( props ) {
	const { defaultActiveTabIndex, Widget, WidgetReportError } = props;

	const [ trackedWidgetView, setTrackedWidgetView ] = useState( false );

	const newIdeas = useSelect( ( select ) =>
		select( MODULES_IDEA_HUB ).getNewIdeas()
	);
	const savedIdeas = useSelect( ( select ) =>
		select( MODULES_IDEA_HUB ).getSavedIdeas()
	);
	const draftIdeas = useSelect( ( select ) =>
		select( MODULES_IDEA_HUB ).getDraftPostIdeas()
	);

	const [ hash, setHash ] = useHash();
	const [ activeTabIndex, setActiveTabIndex ] = useState(
		DashboardIdeasWidget.tabToIndex[ getHash( hash ) ] ||
			defaultActiveTabIndex
	);
	const activeTab = DashboardIdeasWidget.tabIDsByIndex[ activeTabIndex ];

	const [ ideaHubContainer, inView ] = useInView( {
		triggerOnce: true,
		threshold: 0.25,
	} );

	useEffect( () => {
		if ( inView ) {
			trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'widget_view' );
		}
	}, [ inView ] );

	let hasNoIdeas, hasManyIdeas;

	if (
		newIdeas?.length === 0 &&
		savedIdeas?.length === 0 &&
		draftIdeas?.length === 0
	) {
		hasNoIdeas = true;
	}

	if (
		newIdeas?.length > 0 ||
		savedIdeas?.length > 0 ||
		draftIdeas?.length > 0
	) {
		hasManyIdeas = true;
	}

	useEffect( () => {
		// Do nothing if the following events have already been tracked
		// or the widget hasn't appeared in the viewport yet.
		if ( trackedWidgetView || ! inView ) {
			return;
		}

		if ( hasNoIdeas ) {
			setTrackedWidgetView( true );

			trackEvent(
				IDEA_HUB_GA_CATEGORY_WIDGET,
				'widget_gathering_data_view'
			);
		} else if ( hasManyIdeas ) {
			setTrackedWidgetView( true );

			trackEvent(
				IDEA_HUB_GA_CATEGORY_WIDGET,
				'default_tab_view',
				DashboardIdeasWidget.tabIDsByIndex[ activeTabIndex ]
			);
		}
	}, [
		hasNoIdeas,
		hasManyIdeas,
		trackedWidgetView,
		setTrackedWidgetView,
		activeTabIndex,
		inView,
	] );

	useMount( () => {
		if ( ! ideaHubContainer?.current || ! isValidHash( hash ) ) {
			return;
		}

		setTimeout( () => {
			global.window.scrollTo( {
				top: getIdeaHubContainerOffset(
					ideaHubContainer.current.getBoundingClientRect().top
				),
				behavior: 'smooth',
			} );
		}, 1000 );
	} );

	const handleTabUpdate = useCallback(
		( tabIndex ) => {
			const slug = DashboardIdeasWidget.tabIDsByIndex[ tabIndex ];

			setActiveTabIndex( tabIndex );
			setHash( slug );

			trackEvent( IDEA_HUB_GA_CATEGORY_WIDGET, 'tab_select', slug );
		},
		[ setHash, setActiveTabIndex ]
	);

	if ( hasNoIdeas ) {
		return (
			<Widget noPadding>

					<Empty
						Icon={ <EmptyIcon /> }
						title={ __(
							'Idea Hub is generating ideas',
							'google-site-kit'
						) }
						subtitle={ __(
							'This could take 24 hours.',
							'google-site-kit'
						) }
					/>

			</Widget>
		);
	}

	const WrappedFooter = () => (

	);

	return (
		<Widget noPadding Footer={ WrappedFooter }>

						{ __(
							'Ideas to write about based on unanswered searches',
							'google-site-kit'
						) }

					<TabBar
						activeIndex={ activeTabIndex }
						handleActiveIndexUpdate={ handleTabUpdate }
						className="googlesitekit-idea-hub__tabs"
					>
						<Tab focusOnActivate={ false }>
							{ __( 'New', 'google-site-kit' ) }
						</Tab>
						<Tab focusOnActivate={ false }>
							{ savedIdeas?.length >= 0 &&
								createInterpolateElement(
									sprintf(
										/* translators: %s: number of saved Idea Hub ideas */
										__(
											'Saved (%s)',
											'google-site-kit'
										),
										savedIdeas.length
									),
									{
										span: ,
									}
								) }
							{ savedIdeas?.length === undefined &&
								__( 'Saved', 'google-site-kit' ) }
						</Tab>
						<Tab focusOnActivate={ false }>
							{ draftIdeas?.length >= 0 &&
								createInterpolateElement(
									sprintf(
										/* translators: %s: number of draft Idea Hub ideas */
										__(
											'Drafts (%s)',
											'google-site-kit'
										),
										draftIdeas.length
									),
									{
										span: ,
									}
								) }
							{ draftIdeas?.length === undefined &&
								__( 'Drafts', 'google-site-kit' ) }
						</Tab>
					</TabBar>

						<NewIdeas WidgetReportError={ WidgetReportError } />

						<SavedIdeas WidgetReportError={ WidgetReportError } />

						<DraftIdeas WidgetReportError={ WidgetReportError } />

		</Widget>
	);
}

DashboardIdeasWidget.tabToIndex = {
	'new-ideas': 0,
	'saved-ideas': 1,
	'draft-ideas': 2,
};

DashboardIdeasWidget.tabIDsByIndex = Object.keys(
	DashboardIdeasWidget.tabToIndex
);

DashboardIdeasWidget.propTypes = {
	Widget: PropTypes.elementType.isRequired,
	defaultActiveTabIndex: PropTypes.number,
};

DashboardIdeasWidget.defaultProps = {
	defaultActiveTabIndex: 0,
};

export default whenActive( {
	moduleName: 'idea-hub',
	FallbackComponent: DashboardCTA,
} )( DashboardIdeasWidget );
<|endoftext|>


<commit_before>/*
 * step21.js:
 * Requires the following modules:
 *        Module
 *        NB
 *        Auth
 *        jquery
 *
 *
 Author
 cf AUTHORS.txt

 License
 Copyright (c) 2010-2012 Massachusetts Institute of Technology.
 MIT License (cf. MIT-LICENSE.txt or http://www.opensource.org/licenses/mit-license.php)
*/
/*global NB$:true NB:true*/

define(function(require) {
  var $               = require('jquery'),
      concierge       = require('concierge'),
      Pers            = require('pers'),
      Conf            = require('conf'),
      Models          = require('models'),
      perspective     = require('perspective'),
      treeview        = require('treeview'),
      filesview       = require('filesview'),
      Auth            = require('auth'),
      breadcrumb      = require('breadcrumb'),
      files           = require('files');

  if ('NB$' in window) {
    var $ = NB$;
  }

  var $str        = 'NB$' in window ? 'NB$' : 'jQuery';

  Pers.init = function () {
    //pers.admin=true;
    //Extra menus:
    if (!(Conf.userinfo.guest)) {
      $('#menu_settings').after("
Create a new class.
");
    }

    //Factories: methods called if an event calls for a function that's not yet present
    $.concierge.addFactory('admin_init', 'admin_viewer', function (id) {
      var pers_id        = 'pers_' + id;
      var $vp        = $("

").prependTo('body');

      // Add breadcrumb
      $(".nb-widget-header").breadcrumb({
        trail: [{name: "Home", rel: "ensemble", id_item: null}],
        admin: Pers.admin});
      $(".nb-widget-header").breadcrumb("set_model", Pers.store);

      var $pers        = $("
").appendTo($vp);
      var treeview    =  {
        priority: 1,
        min_width: 200,
        desired_width: 25,
        content: function ($div) {
          $div.treeView({ admin: Pers.admin });
          $div.treeView('set_model', Pers.store);

          //default behavior: select the "home" screen.
          $.concierge.trigger({ type:'ensemble', value: 0 });
        },
      };
      var filesview    =  {
        priority: 1,
        min_width: 1000,
        desired_width: 85,
        content: function ($div) {
          $div.filesView({ img_server: Conf.servers.img,  admin: Pers.admin });
          $div.filesView('set_model', Pers.store);
        },
      };
      $pers.perspective({
        height: function () {return $vp.height() - $pers.offset().top;},

        listens: {
          rate_reply: function (evt) {
            $.concierge.get_component('rate_reply')(evt.value, function (P) {
              Pers.store.add('replyrating', P['replyrating']);
              $.I('Thanks for your feedback !');
            });
          },

          successful_login: function (evt) {
            Auth.set_cookie('ckey', evt.value.ckey);
            document.location = 'http://' + document.location.host + document.location.pathname;
            $.I('Welcome !');
          },

          close_view: function (evt) {
            if (evt.value === this.l.element[0].id) {
              delete($.concierge.features.doc_viewer[id]);
            }

            $.L('closeview: ', evt, this.l.element[0].id);
          },

          ensemble: function (evt) {
            $.L('loading stats for ensemble' + evt.value);
            $.concierge.get_component('get_file_stats')({ id_ensemble: evt.value }, function (P2) {
              Pers.store.add('file_stats', P2['file_stats']);
              $.L('stats loaded !');
            });
            var ensemble_data = Pers.store.o.ensemble;
            // Update breadcrumb
            if(evt.value === null || evt.value === undefined || evt.value === "0" ) { // home
              $(".nb-widget-header").breadcrumb({trail: [
                {name: "Home", rel: "ensemble", id_item: null},
              ]});
            } else {
              $(".nb-widget-header").breadcrumb({trail: [
                {name: "Home", rel: "ensemble", id_item: null},
                {name: ensemble_data[evt.value].name, rel: "ensemble", id_item: evt.value}
              ]});
            }

          },

          folder: function(evt) {
            // Folder data from the server
            var folder_data = Pers.store.o.folder;
            var ensemble_data = Pers.store.o.ensemble;

            // Create trail starting with Home and the ensemble
            var id_ensemble = folder_data[evt.value].id_ensemble;

            var trail = [
              {name: "Home", rel: "ensemble", id_item: null},
              {name: ensemble_data[id_ensemble].name, rel: "ensemble", id_item: id_ensemble}
            ];

            // Loop through fdata to generate list of parent folders
            var cur_folder = evt.value;
            var parent_folders = [cur_folder];
            while(folder_data[cur_folder].id_parent != null) {
              cur_folder = folder_data[cur_folder].id_parent;
              parent_folders.push(cur_folder);
            }

            // Add parents to trail
            while(parent_folders.length>0) {
              var cur_id = parent_folders.pop();
              trail.push({
                name: folder_data[cur_id].name,
                rel: "folder",
                id_item: cur_id
              });
            }

            // Update breadcrumb
            $(".nb-widget-header").breadcrumb({trail: trail});
          },
        },
        views: {
    v1:{ data: treeview },
            v2:{ data: filesview }, orientation: 'vertical', },
      });
    });

    //get data:
    var payload_objects = { types: ['ensembles', 'folders', 'files', 'sections'] };
    if ('id_ensemble' in Pers.params) {
      payload_objects['payload'] = { id_ensemble: Pers.params.id_ensemble };
    }

    Pers.call('getObjects', payload_objects, Pers.createStore);
    $.concierge.addComponents({
      add_file_menu: function (P, cb) {files.addFile(P.id_ensemble, P.id_folder);},

      source_id_getter: function (P, cb) {Pers.call('request_source_id', P, cb);},

      add_folder_menu: function (P, cb) {files.addFolder(P.id_ensemble, P.id_folder);},

      add_folder: function (P, cb) {Pers.call('add_folder', P, cb);},

      rename_file_menu: function (P, cb) {files.rename_file(P.id, P.item_type);},

      rename_file: function (P, cb) {Pers.call('rename_file', P, cb);},

      delete_file_menu: function (P, cb) {files.delete_file(P.id, P.item_type);},

      delete_file: function (P, cb) {Pers.call('delete_file', P, cb);},

      move_file_menu: function (P, cb) {files.move_file(P.id, P.item_type);},

      move_file: function (P, cb) {Pers.call('move_file', P, cb);},

      duplicate_file_menu: function (P, cb) {files.duplicate_file(P.id, P.item_type);},

      update_file_menu: function (P, cb) {files.update_file(P.id);},

      add_ensemble_menu: function (P, cb) {files.addEnsemble();},

      add_ensemble: function (P, cb) {Pers.call('add_ensemble', P, cb);},

      invite_users_menu: function (P, cb) {files.inviteUsers(P.id_ensemble);},

      invite_users: function (P, cb) {Pers.call('sendInvites', P, cb);},

      assignment_file_menu: function (P, cb) {files.edit_assignment(P.id);},

      edit_assignment: function (P, cb) {Pers.call('edit_assignment', P, cb);},

      get_top_comments_from_locations: function (P, cb) {
        Pers.call('get_top_comments_from_locations', P, cb);
      },

      copy_file: function (P, cb) {
        Pers.call('copy_file', {
          source_id: P.source_id,
          target_name: P.target_name,
          target_id: P.target_id,
          target_type: P.target_type,
        }, cb);
      },

      bulk_import_annotations: function (P, cb) {
        Pers.call('bulk_import_annotations', {
          locs_array: P.locs_array,
          from_source_id: P.from_source_id,
          to_source_id: P.to_source_id,
          import_type: P.import_type,
        }, cb);
      },
    });

    $.concierge.addComponents({
      notes_loader:    function (P, cb) {Pers.call('getNotes', P, cb);},

      note_creator:    function (P, cb) {Pers.call('saveNote', P, cb);},

      note_editor:    function (P, cb) {Pers.call('editNote', P, cb);},
    });
  };

  Pers.createStore = function (payload) {
    Pers.store = new Models.Store();
    Pers.store.create(payload, {
      ensemble:    { pFieldName: 'ensembles' },
      section:    { pFieldName: 'sections', references: { id_ensemble: 'ensemble' } },
      file:    { pFieldName: 'files', references: { id_ensemble: 'ensemble', id_folder: 'folder' } },
      folder: { pFieldName: 'folders', references: { id_ensemble: 'ensemble', id_parent: 'folder' } },
      comment:{ references: { id_location: 'location' } },
      location:{ references: { id_ensemble: 'ensemble', id_source: 'file' } },
      link: { pFieldName: 'links' },
      file_stats:{ references: { id: 'file' } },
      mark: {},
      draft: {},
      question: { references: { location_id: 'location' } },
      seen:{ references: { id_location: 'location' } },
      basecomment:{ references: { id_location: 'location' } },
      replyrating:{ references: { comment_id: 'comment' } },
    });
    var cb2 = function (P2) {
      var m = Pers.store;
      m.set('location', P2['locations']);
      m.set('comment', P2['comments']);
      m.set('basecomment', P2['basecomments']);
      m.set('question', P2['questions']);
    };

    $.concierge.setHistoryHelper(function (_payload, cb) {
      _payload['__return'] = { type:'newPending', a:{} };
      Pers.call('log_history', _payload, cb);
    }, 120000, cb2, 600000);

    files.set_model(Pers.store);
    $.concierge.trigger({ type:'admin_init', value: 0 });

    //get more stats (pending stuff)
    Pers.call('getPending', {}, function (P) {
      Pers.store.add('location', P['locations']);
      Pers.store.add('comment', P['comments']);
      Pers.store.add('basecomment', P['basecomments']);
      Pers.store.add('question', P['questions']);
    });

  };
});
<commit_msg>Quick fix to 'Create a new class' button'<commit_after>/*
 * step21.js:
 * Requires the following modules:
 *        Module
 *        NB
 *        Auth
 *        jquery
 *
 *
 Author
 cf AUTHORS.txt

 License
 Copyright (c) 2010-2012 Massachusetts Institute of Technology.
 MIT License (cf. MIT-LICENSE.txt or http://www.opensource.org/licenses/mit-license.php)
*/
/*global NB$:true NB:true*/

define(function(require) {
  var $               = require('jquery'),
      concierge       = require('concierge'),
      Pers            = require('pers'),
      Conf            = require('conf'),
      Models          = require('models'),
      perspective     = require('perspective'),
      treeview        = require('treeview'),
      filesview       = require('filesview'),
      Auth            = require('auth'),
      breadcrumb      = require('breadcrumb'),
      files           = require('files');

  if ('NB$' in window) {
    var $ = NB$;
  }

  var $str        = 'NB$' in window ? 'NB$' : 'jQuery';

  Pers.init = function () {
    //pers.admin=true;
    //Extra menus:
    if (!(Conf.userinfo.guest)) {
      $('#menu_settings').after("
Create a new class.
");
    }

    //Factories: methods called if an event calls for a function that's not yet present
    $.concierge.addFactory('admin_init', 'admin_viewer', function (id) {
      var pers_id        = 'pers_' + id;
      var $vp        = $("

").prependTo('body');

      // Add breadcrumb
      $(".nb-widget-header").breadcrumb({
        trail: [{name: "Home", rel: "ensemble", id_item: null}],
        admin: Pers.admin});
      $(".nb-widget-header").breadcrumb("set_model", Pers.store);

      var $pers        = $("
").appendTo($vp);
      var treeview    =  {
        priority: 1,
        min_width: 200,
        desired_width: 25,
        content: function ($div) {
          $div.treeView({ admin: Pers.admin });
          $div.treeView('set_model', Pers.store);

          //default behavior: select the "home" screen.
          $.concierge.trigger({ type:'ensemble', value: 0 });
        },
      };
      var filesview    =  {
        priority: 1,
        min_width: 1000,
        desired_width: 85,
        content: function ($div) {
          $div.filesView({ img_server: Conf.servers.img,  admin: Pers.admin });
          $div.filesView('set_model', Pers.store);
        },
      };
      $pers.perspective({
        height: function () {return $vp.height() - $pers.offset().top;},

        listens: {
          rate_reply: function (evt) {
            $.concierge.get_component('rate_reply')(evt.value, function (P) {
              Pers.store.add('replyrating', P['replyrating']);
              $.I('Thanks for your feedback !');
            });
          },

          successful_login: function (evt) {
            Auth.set_cookie('ckey', evt.value.ckey);
            document.location = 'http://' + document.location.host + document.location.pathname;
            $.I('Welcome !');
          },

          close_view: function (evt) {
            if (evt.value === this.l.element[0].id) {
              delete($.concierge.features.doc_viewer[id]);
            }

            $.L('closeview: ', evt, this.l.element[0].id);
          },

          ensemble: function (evt) {
            $.L('loading stats for ensemble' + evt.value);
            $.concierge.get_component('get_file_stats')({ id_ensemble: evt.value }, function (P2) {
              Pers.store.add('file_stats', P2['file_stats']);
              $.L('stats loaded !');
            });
            var ensemble_data = Pers.store.o.ensemble;
            // Update breadcrumb
            if(evt.value === null || evt.value === undefined || evt.value === "0" ) { // home
              $(".nb-widget-header").breadcrumb({trail: [
                {name: "Home", rel: "ensemble", id_item: null},
              ]});
            } else {
              $(".nb-widget-header").breadcrumb({trail: [
                {name: "Home", rel: "ensemble", id_item: null},
                {name: ensemble_data[evt.value].name, rel: "ensemble", id_item: evt.value}
              ]});
            }

          },

          folder: function(evt) {
            // Folder data from the server
            var folder_data = Pers.store.o.folder;
            var ensemble_data = Pers.store.o.ensemble;

            // Create trail starting with Home and the ensemble
            var id_ensemble = folder_data[evt.value].id_ensemble;

            var trail = [
              {name: "Home", rel: "ensemble", id_item: null},
              {name: ensemble_data[id_ensemble].name, rel: "ensemble", id_item: id_ensemble}
            ];

            // Loop through fdata to generate list of parent folders
            var cur_folder = evt.value;
            var parent_folders = [cur_folder];
            while(folder_data[cur_folder].id_parent != null) {
              cur_folder = folder_data[cur_folder].id_parent;
              parent_folders.push(cur_folder);
            }

            // Add parents to trail
            while(parent_folders.length>0) {
              var cur_id = parent_folders.pop();
              trail.push({
                name: folder_data[cur_id].name,
                rel: "folder",
                id_item: cur_id
              });
            }

            // Update breadcrumb
            $(".nb-widget-header").breadcrumb({trail: trail});
          },
        },
        views: {
    v1:{ data: treeview },
            v2:{ data: filesview }, orientation: 'vertical', },
      });
    });

    //get data:
    var payload_objects = { types: ['ensembles', 'folders', 'files', 'sections'] };
    if ('id_ensemble' in Pers.params) {
      payload_objects['payload'] = { id_ensemble: Pers.params.id_ensemble };
    }

    Pers.call('getObjects', payload_objects, Pers.createStore);
    $.concierge.addComponents({
      add_file_menu: function (P, cb) {files.addFile(P.id_ensemble, P.id_folder);},

      source_id_getter: function (P, cb) {Pers.call('request_source_id', P, cb);},

      add_folder_menu: function (P, cb) {files.addFolder(P.id_ensemble, P.id_folder);},

      add_folder: function (P, cb) {Pers.call('add_folder', P, cb);},

      rename_file_menu: function (P, cb) {files.rename_file(P.id, P.item_type);},

      rename_file: function (P, cb) {Pers.call('rename_file', P, cb);},

      delete_file_menu: function (P, cb) {files.delete_file(P.id, P.item_type);},

      delete_file: function (P, cb) {Pers.call('delete_file', P, cb);},

      move_file_menu: function (P, cb) {files.move_file(P.id, P.item_type);},

      move_file: function (P, cb) {Pers.call('move_file', P, cb);},

      duplicate_file_menu: function (P, cb) {files.duplicate_file(P.id, P.item_type);},

      update_file_menu: function (P, cb) {files.update_file(P.id);},

      add_ensemble_menu: function (P, cb) {files.addEnsemble();},

      add_ensemble: function (P, cb) {Pers.call('add_ensemble', P, cb);},

      invite_users_menu: function (P, cb) {files.inviteUsers(P.id_ensemble);},

      invite_users: function (P, cb) {Pers.call('sendInvites', P, cb);},

      assignment_file_menu: function (P, cb) {files.edit_assignment(P.id);},

      edit_assignment: function (P, cb) {Pers.call('edit_assignment', P, cb);},

      get_top_comments_from_locations: function (P, cb) {
        Pers.call('get_top_comments_from_locations', P, cb);
      },

      copy_file: function (P, cb) {
        Pers.call('copy_file', {
          source_id: P.source_id,
          target_name: P.target_name,
          target_id: P.target_id,
          target_type: P.target_type,
        }, cb);
      },

      bulk_import_annotations: function (P, cb) {
        Pers.call('bulk_import_annotations', {
          locs_array: P.locs_array,
          from_source_id: P.from_source_id,
          to_source_id: P.to_source_id,
          import_type: P.import_type,
        }, cb);
      },
    });

    $.concierge.addComponents({
      notes_loader:    function (P, cb) {Pers.call('getNotes', P, cb);},

      note_creator:    function (P, cb) {Pers.call('saveNote', P, cb);},

      note_editor:    function (P, cb) {Pers.call('editNote', P, cb);},
    });
  };

  Pers.createStore = function (payload) {
    Pers.store = new Models.Store();
    Pers.store.create(payload, {
      ensemble:    { pFieldName: 'ensembles' },
      section:    { pFieldName: 'sections', references: { id_ensemble: 'ensemble' } },
      file:    { pFieldName: 'files', references: { id_ensemble: 'ensemble', id_folder: 'folder' } },
      folder: { pFieldName: 'folders', references: { id_ensemble: 'ensemble', id_parent: 'folder' } },
      comment:{ references: { id_location: 'location' } },
      location:{ references: { id_ensemble: 'ensemble', id_source: 'file' } },
      link: { pFieldName: 'links' },
      file_stats:{ references: { id: 'file' } },
      mark: {},
      draft: {},
      question: { references: { location_id: 'location' } },
      seen:{ references: { id_location: 'location' } },
      basecomment:{ references: { id_location: 'location' } },
      replyrating:{ references: { comment_id: 'comment' } },
    });
    var cb2 = function (P2) {
      var m = Pers.store;
      m.set('location', P2['locations']);
      m.set('comment', P2['comments']);
      m.set('basecomment', P2['basecomments']);
      m.set('question', P2['questions']);
    };

    $.concierge.setHistoryHelper(function (_payload, cb) {
      _payload['__return'] = { type:'newPending', a:{} };
      Pers.call('log_history', _payload, cb);
    }, 120000, cb2, 600000);

    files.set_model(Pers.store);
    $.concierge.trigger({ type:'admin_init', value: 0 });

    //get more stats (pending stuff)
    Pers.call('getPending', {}, function (P) {
      Pers.store.add('location', P['locations']);
      Pers.store.add('comment', P['comments']);
      Pers.store.add('basecomment', P['basecomments']);
      Pers.store.add('question', P['questions']);
    });

  };
});
<|endoftext|>


<commit_before>console.time("Tests");

selfJoin.assert({maxTests: 1000});
productJoin.assert({maxTests: 1000, maxSize: 200});
constantJoin.assert({maxTests: 1000});
incrementalConstantJoin.assert({maxTests: 1000});
actualJoin.assert({maxTests: 1000, maxSize: 200});
incrementalActualJoin.assert({maxTests: 1000, maxSize: 200});
functionJoin.assert({maxTests: 1000, maxSize: 100});
incrementalFunctionJoin.assert({maxTests: 1000, maxSize: 50});
negatedJoin.assert({maxTests: 1000});
incrementalNegatedJoin.assert({maxTests: 1000});

compiledPathTest();
compiledFunctionTest();
compiledNegationTest();

console.timeEnd("Tests");
<commit_msg>Add timers to tests so that CI doesnt give up<commit_after>console.time("selfJoin");
selfJoin.assert({maxTests: 1000});
console.timeEnd("selfJoin");

console.time("productJoin");
productJoin.assert({maxTests: 1000, maxSize: 200});
console.timeEnd("productJoin");

console.time("constantJoin");
constantJoin.assert({maxTests: 1000});
console.timeEnd("constantJoin");

console.time("incrementalConstantJoin");
incrementalConstantJoin.assert({maxTests: 1000});
console.timeEnd("incrementalConstantJoin")

console.time("actualJoin");
actualJoin.assert({maxTests: 1000, maxSize: 200});
console.timeEnd("actualJoin");

console.time("incrementalActualJoin");
incrementalActualJoin.assert({maxTests: 1000, maxSize: 200});
console.timeEnd("incrementalActualJoin");

console.time("functionJoin");
functionJoin.assert({maxTests: 1000, maxSize: 100});
console.timeEnd("functionJoin");

console.time("incrementalFunctionJoin");
incrementalFunctionJoin.assert({maxTests: 1000, maxSize: 50});
console.timeEnd("incrementalFunctionJoin");

console.time("negatedJoin");
negatedJoin.assert({maxTests: 1000});
console.timeEnd("negatedJoin");

console.time("incrementalNegatedJoin");
incrementalNegatedJoin.assert({maxTests: 1000});
console.timeEnd("incrementalNegatedJoin");

console.time("Compiler tests")
compiledPathTest();
compiledFunctionTest();
compiledNegationTest();
console.timeEnd("Compiler tests");
<|endoftext|>