<commit_before>/**
 * @author Ludvig Boström, c13lbm
 */

/**
 * Creates a list out of an object containing multiple items.
 * @param obj
 * @returns {Array}
 */
var objToList = function (obj) {
    if(typeof obj !== "undefined"){
        var res = Object.keys(obj).map(function(key){
            return obj[key];
        });
        return res;
    }
    else {
        return [];
    }

}

var StudentOptions = React.createClass({

    galleryClick: function () {

        var assID = this.props.assignment.assignment.assignmentID;
        var courseID = this.props.courseId;
        var userID = this.props.courseId;

        ReactDOM.render(<StudentVideoGallery userID={userID} courseID={courseID} assID={assID} />,
                    document.getElementById('courseContent'));

    },
    render: function () {
        return (

                      Submission Gallery

        );
    }

});

var Options = React.createClass({

    studentClick: function () {
        var assID = this.props.assignment.assignment.assignmentID;
        var courseID = this.props.courseId;
        var l = new Date();
        var now = l.getTime() - (l.getTimezoneOffset() * 60000);

        var eDate = new Date(this.props.assignment.assignment.assignmentIntervall.endDate.split(' ').join('T')).getTime();
        if(objToList(this.props.assignment.submissions).length == 0 &&
            eDate >= now){

                ReactDOM.render(<AssignmentContent uid={this.props.uid} course={courseID} assignment={assID}/>,
                document.getElementById('courseContent'));
        }
        else {
            ReactDOM.render(<Feedback course={courseID} assignment={assID} user={this.props.uid}/>,
                document.getElementById('courseContent'));
        }

    },
    editClick: function () {
        var assID = this.props.assignment.assignment.assignmentID;
        var courseID = this.props.courseId;
        ReactDOM.render(<NewAssignment edit={true} courseID={courseID} assID={assID} uid={this.props.uid}/>,document.getElementById("courseContent"))
    },
    deleteClick: function () {
        var assID = this.props.assignment.assignment.assignmentID;
        var courseID = this.props.courseId;
        var reqBody = {};

        reqBody["courseID"] = courseID;
        $.ajax({
            type : "DELETE",
            url : "assignments/" + assID + "?courseID=" + courseID,
            timeout : 100000,
            success : function(response) {
                alert("Removed assignment");
            },
            error : function(e) {
                console.log(e);
                alert("Failed to remove assignment. The assignment may have submissions or it doesn't exist");
            },
            done : function(e) {
                console.log("DONE");
            }
        });
    },
    galleryClick: function () {

        var assID = this.props.assignment.assignment.assignmentID;
        var courseID = this.props.courseId;
        var userID = this.props.courseId;
        this.forceUpdate();

        ReactDOM.render(<StudentVideoGallery userID={userID} courseID={courseID} assID={assID} />,
                    document.getElementById('courseContent'));

    },

    render: function () {
        return (

                        Student view

                        Edit Assignment

                        Delete Assignment

                        Submission Gallery

        );
    }
});

/*  Here assignment information is displayed.
 */
var Assignment = React.createClass({

    getInitialState : function() {
        return { showChildren : false };
    },

    /**
     * Render different views depending on user role on course.
     * @param assignment
     * @param event
     */
    handleClick: function(assignment,event) {
        var uid = this.props.uid;
        var assID = this.props.assignment.assignment.assignmentID;
        var courseID = this.props.courseId;
        if(this.props.role == "student"){
            var l = new Date();
            var now = l.getTime() - (l.getTimezoneOffset() * 60000);

            var eDate = new Date(this.props.assignment.assignment.assignmentIntervall.endDate.split(' ').join('T')).getTime();
            if(objToList(this.props.assignment.submissions).length == 0 &&
                eDate >= now){
                ReactDOM.render(<AssignmentContent uid={uid} course={courseID} assignment={assID}/>,
                    document.getElementById('courseContent'));
            }
            else {
                ReactDOM.render(<Feedback course={courseID} assignment={assID} user={uid}/>,
                    document.getElementById('courseContent'));
            }

        }
        else if(this.props.role == "teacher"){
            var scale = this.props.assignment.assignment.scale;
            document.getElementById("courseContent").innerHTML = "";
            ReactDOM.render(<TeacherViewSubmission courseId={courseID} assignmentId={assID} scale={scale}/>,
                                document.getElementById('courseContent') );
        }
        this.setState({showChildren:!this.state.showChildren});

    },
    /**
     * Render list item for this assigment. Set active if between startdate and enddate.
     * @returns {XML}
     */
    render: function (){
        var assignment = this.props.assignment;
        var classname = "assignment menuItem navigationText";
        var l = new Date();

        var now = l.getTime() - (l.getTimezoneOffset() * 60000);
        var sDate = new Date(assignment.assignment.assignmentIntervall.startDate.split(' ').join('T')).getTime();
        var eDate = new Date(assignment.assignment.assignmentIntervall.endDate.split(' ').join('T')).getTime();

        var options = "";
        if(this.state.showChildren && this.props.role == "teacher"){
            options = <Options assignment={assignment} courseId={this.props.courseId} uid={this.props.uid}/>;
        } else if(this.state.showChildren && this.props.role == "student"){
            options = <StudentOptions assignment={assignment} courseId={this.props.courseId} uid={this.props.uid}/>;
        }

        if(sDate <= now &&
            eDate >= now)
            classname += " active";

        return

{assignment.assignment.title}
{options}
;
    }
});

var Assignments = React.createClass({
    /**
     * render the new assignment page
     * @param course
     * @param event
     */
    handleClick: function (course, event) {
        ReactDOM.render(<NewAssignment edit={false} courseID={course.courseId} courseCode={course.courseCode} uid={this.props.uid}/>,document.getElementById("courseContent"))
    },
    /**
     * Get the course information and render the edit course page passing course and user id as props.
     * @param course
     * @param event
     */
    editClick: function (course,event) {
        var uid = this.props.uid;
        $.get("course/" + course.courseId,function (res) {
            ReactDOM.render(<EditCourse course={res} uid={uid}/>,document.getElementById("courseContent"));

        });

    },
    /**
     * Create a list of assignments and append teacher specific options for teachers.
     * @returns {XML}
     */
    render: function() {
        var uid = this.props.uid;
        var course = this.props.course;
        var role = this.props.role;
        var assignments = objToList(course.assignments);
        var assList = assignments.map(function (ass) {
            return <Assignment key={ass.assignment.assignmentID} courseId={course.course.courseId} assignment={ass} uid={uid} role={role}/>
        });
        if(role=="teacher"){
            assList.push(

                        + New Assignment

            );
            assList.push(

                        Edit Course

            );
        }

        return
{assList}
;
    }
});
var Course = React.createClass({
    getInitialState : function() {
        return { showChildren : false };
    },

    handleClick: function(course,event) {
        var role = this.props.role;
        $.get("course/" + course.course.courseId,function (res) {
            ReactDOM.render(<CourseInfo course={res} role={role}/>,document.getElementById("courseContent"));

        });

        this.setState({showChildren:!this.state.showChildren});

    },
    render: function (){
        var course = this.props.course;
        var classname = "course menuItem navigationText";
        var assignments = "";

        if(this.state.showChildren || preload == course.course.courseId){
            assignments = <Assignments course={course} role={this.props.role} uid={this.props.uid}/>;
            this.state.showChildren = true;
            preload = null;
        }

        if(course.course.active)
            classname += " active";

        return

{course.course.courseName}
{assignments}

    }
});

/**
 * Main menu rendering.
 */
var DynamicMenu = React.createClass({
    /**
     * Render createCourse page on clicking the menu item.
     * @param userID
     * @param event
     */
    handleClick: function (userID,event) {
        ReactDOM.render(<CreateCourse uid={userID}/>,document.getElementById("courseContent"));
    },

    searchClick: function (userID,event) {
        ReactDOM.render(<SearchCourse/>,document.getElementById("courseContent"))
    },

    /**
     * Makes separate lists for student/teacher courses. Only gives teachers the option to create course.
     * @returns {XML}
     */
    render: function () {

        var teach;
        var stud;
        var uid = this.props.uid;
        var preload = this.props.preload;
        if(this.props.tList.length > 0){
            var tList = this.props.tList.map(function(tCourse){
                return <Course key={tCourse.course.courseId} course={tCourse} uid={uid} role="teacher"/>
            });
            teach =

Teacher:

                        {tList}

        }
        if(this.props.sList.length > 0){
            var sList = this.props.sList.map(function(sCourse){
                return <Course key={sCourse.course.courseId} course={sCourse} uid={uid} role="student" />
            });
            stud =

Student:

                            {sList}

        }
        var newItem = "";
        if(this.props.isTeacher){
            var newItem =

                    + New Course

;
        }

        return (

                {teach}
                {stud}

                    {newItem}

        );
    }
});

/**
 * Function to get the hierachical structure of the menu
 * and then render the menus.
 *
 */
window.RenderMenu = function (preloaded) {
    $.get("course", function (res) {
        // if(res)
        var userID = res.userId;
        //console.log(res);
        var SCList = objToList(res.studentCourses);
        var TCList = objToList(res.teacherCourses);
        var name = res.firstName + " " + res.lastName;
        preload = preloaded;
        ReactDOM.render(<DynamicMenu tList={TCList} sList={SCList} uid={userID} isTeacher={res.isTeacher}/>, document.getElementById("desktopNavigation"));

        ReactDOM.render(<NewProfile name={name} uid={userID}/>, document.getElementById('desktopHeader'));
    });
};

/**
 * If menu will have a specific course preselected.
 */
var preload;
if(window.getQueryVariable("param") == false){
    RenderMenu();
}
<commit_msg>Hide (comment out) faulty student gallery<commit_after>/**
 * @author Ludvig Boström, c13lbm
 */

/**
 * Creates a list out of an object containing multiple items.
 * @param obj
 * @returns {Array}
 */
var objToList = function (obj) {
    if(typeof obj !== "undefined"){
        var res = Object.keys(obj).map(function(key){
            return obj[key];
        });
        return res;
    }
    else {
        return [];
    }

}

var StudentOptions = React.createClass({

    galleryClick: function () {

        var assID = this.props.assignment.assignment.assignmentID;
        var courseID = this.props.courseId;
        var userID = this.props.courseId;

        ReactDOM.render(<StudentVideoGallery userID={userID} courseID={courseID} assID={assID} />,
                    document.getElementById('courseContent'));

    },
    render: function () {
        return (

                      Submission Gallery

        );
    }

});

var Options = React.createClass({

    studentClick: function () {
        var assID = this.props.assignment.assignment.assignmentID;
        var courseID = this.props.courseId;
        var l = new Date();
        var now = l.getTime() - (l.getTimezoneOffset() * 60000);

        var eDate = new Date(this.props.assignment.assignment.assignmentIntervall.endDate.split(' ').join('T')).getTime();
        if(objToList(this.props.assignment.submissions).length == 0 &&
            eDate >= now){

                ReactDOM.render(<AssignmentContent uid={this.props.uid} course={courseID} assignment={assID}/>,
                document.getElementById('courseContent'));
        }
        else {
            ReactDOM.render(<Feedback course={courseID} assignment={assID} user={this.props.uid}/>,
                document.getElementById('courseContent'));
        }

    },
    editClick: function () {
        var assID = this.props.assignment.assignment.assignmentID;
        var courseID = this.props.courseId;
        ReactDOM.render(<NewAssignment edit={true} courseID={courseID} assID={assID} uid={this.props.uid}/>,document.getElementById("courseContent"))
    },
    deleteClick: function () {
        var assID = this.props.assignment.assignment.assignmentID;
        var courseID = this.props.courseId;
        var reqBody = {};

        reqBody["courseID"] = courseID;
        $.ajax({
            type : "DELETE",
            url : "assignments/" + assID + "?courseID=" + courseID,
            timeout : 100000,
            success : function(response) {
                alert("Removed assignment");
            },
            error : function(e) {
                console.log(e);
                alert("Failed to remove assignment. The assignment may have submissions or it doesn't exist");
            },
            done : function(e) {
                console.log("DONE");
            }
        });
    },
    galleryClick: function () {

        var assID = this.props.assignment.assignment.assignmentID;
        var courseID = this.props.courseId;
        var userID = this.props.courseId;
        this.forceUpdate();

        ReactDOM.render(<StudentVideoGallery userID={userID} courseID={courseID} assID={assID} />,
                    document.getElementById('courseContent'));

    },

    render: function () {
        return (

                        Student view

                        Edit Assignment

                        Delete Assignment

                {/*

                        Submission Gallery

*/}

        );
    }
});

/*  Here assignment information is displayed.
 */
var Assignment = React.createClass({

    getInitialState : function() {
        return { showChildren : false };
    },

    /**
     * Render different views depending on user role on course.
     * @param assignment
     * @param event
     */
    handleClick: function(assignment,event) {
        var uid = this.props.uid;
        var assID = this.props.assignment.assignment.assignmentID;
        var courseID = this.props.courseId;
        if(this.props.role == "student"){
            var l = new Date();
            var now = l.getTime() - (l.getTimezoneOffset() * 60000);

            var eDate = new Date(this.props.assignment.assignment.assignmentIntervall.endDate.split(' ').join('T')).getTime();
            if(objToList(this.props.assignment.submissions).length == 0 &&
                eDate >= now){
                ReactDOM.render(<AssignmentContent uid={uid} course={courseID} assignment={assID}/>,
                    document.getElementById('courseContent'));
            }
            else {
                ReactDOM.render(<Feedback course={courseID} assignment={assID} user={uid}/>,
                    document.getElementById('courseContent'));
            }

        }
        else if(this.props.role == "teacher"){
            var scale = this.props.assignment.assignment.scale;
            document.getElementById("courseContent").innerHTML = "";
            ReactDOM.render(<TeacherViewSubmission courseId={courseID} assignmentId={assID} scale={scale}/>,
                                document.getElementById('courseContent') );
        }
        this.setState({showChildren:!this.state.showChildren});

    },
    /**
     * Render list item for this assigment. Set active if between startdate and enddate.
     * @returns {XML}
     */
    render: function (){
        var assignment = this.props.assignment;
        var classname = "assignment menuItem navigationText";
        var l = new Date();

        var now = l.getTime() - (l.getTimezoneOffset() * 60000);
        var sDate = new Date(assignment.assignment.assignmentIntervall.startDate.split(' ').join('T')).getTime();
        var eDate = new Date(assignment.assignment.assignmentIntervall.endDate.split(' ').join('T')).getTime();

        var options = "";
        if(this.state.showChildren && this.props.role == "teacher"){
            options = <Options assignment={assignment} courseId={this.props.courseId} uid={this.props.uid}/>;
        } /*else if(this.state.showChildren && this.props.role == "student"){
            options = <StudentOptions assignment={assignment} courseId={this.props.courseId} uid={this.props.uid}/>;
        }*/

        if(sDate <= now &&
            eDate >= now)
            classname += " active";

        return

{assignment.assignment.title}
{options}
;
    }
});

var Assignments = React.createClass({
    /**
     * render the new assignment page
     * @param course
     * @param event
     */
    handleClick: function (course, event) {
        ReactDOM.render(<NewAssignment edit={false} courseID={course.courseId} courseCode={course.courseCode} uid={this.props.uid}/>,document.getElementById("courseContent"))
    },
    /**
     * Get the course information and render the edit course page passing course and user id as props.
     * @param course
     * @param event
     */
    editClick: function (course,event) {
        var uid = this.props.uid;
        $.get("course/" + course.courseId,function (res) {
            ReactDOM.render(<EditCourse course={res} uid={uid}/>,document.getElementById("courseContent"));

        });

    },
    /**
     * Create a list of assignments and append teacher specific options for teachers.
     * @returns {XML}
     */
    render: function() {
        var uid = this.props.uid;
        var course = this.props.course;
        var role = this.props.role;
        var assignments = objToList(course.assignments);
        var assList = assignments.map(function (ass) {
            return <Assignment key={ass.assignment.assignmentID} courseId={course.course.courseId} assignment={ass} uid={uid} role={role}/>
        });
        if(role=="teacher"){
            assList.push(

                        + New Assignment

            );
            assList.push(

                        Edit Course

            );
        }

        return
{assList}
;
    }
});
var Course = React.createClass({
    getInitialState : function() {
        return { showChildren : false };
    },

    handleClick: function(course,event) {
        var role = this.props.role;
        $.get("course/" + course.course.courseId,function (res) {
            ReactDOM.render(<CourseInfo course={res} role={role}/>,document.getElementById("courseContent"));

        });

        this.setState({showChildren:!this.state.showChildren});

    },
    render: function (){
        var course = this.props.course;
        var classname = "course menuItem navigationText";
        var assignments = "";

        if(this.state.showChildren || preload == course.course.courseId){
            assignments = <Assignments course={course} role={this.props.role} uid={this.props.uid}/>;
            this.state.showChildren = true;
            preload = null;
        }

        if(course.course.active)
            classname += " active";

        return

{course.course.courseName}
{assignments}

    }
});

/**
 * Main menu rendering.
 */
var DynamicMenu = React.createClass({
    /**
     * Render createCourse page on clicking the menu item.
     * @param userID
     * @param event
     */
    handleClick: function (userID,event) {
        ReactDOM.render(<CreateCourse uid={userID}/>,document.getElementById("courseContent"));
    },

    searchClick: function (userID,event) {
        ReactDOM.render(<SearchCourse/>,document.getElementById("courseContent"))
    },

    /**
     * Makes separate lists for student/teacher courses. Only gives teachers the option to create course.
     * @returns {XML}
     */
    render: function () {

        var teach;
        var stud;
        var uid = this.props.uid;
        var preload = this.props.preload;
        if(this.props.tList.length > 0){
            var tList = this.props.tList.map(function(tCourse){
                return <Course key={tCourse.course.courseId} course={tCourse} uid={uid} role="teacher"/>
            });
            teach =

Teacher:

                        {tList}

        }
        if(this.props.sList.length > 0){
            var sList = this.props.sList.map(function(sCourse){
                return <Course key={sCourse.course.courseId} course={sCourse} uid={uid} role="student" />
            });
            stud =

Student:

                            {sList}

        }
        var newItem = "";
        if(this.props.isTeacher){
            var newItem =

                    + New Course

;
        }

        return (

                {teach}
                {stud}

                    {newItem}

        );
    }
});

/**
 * Function to get the hierachical structure of the menu
 * and then render the menus.
 *
 */
window.RenderMenu = function (preloaded) {
    $.get("course", function (res) {
        // if(res)
        var userID = res.userId;
        //console.log(res);
        var SCList = objToList(res.studentCourses);
        var TCList = objToList(res.teacherCourses);
        var name = res.firstName + " " + res.lastName;
        preload = preloaded;
        ReactDOM.render(<DynamicMenu tList={TCList} sList={SCList} uid={userID} isTeacher={res.isTeacher}/>, document.getElementById("desktopNavigation"));

        ReactDOM.render(<NewProfile name={name} uid={userID}/>, document.getElementById('desktopHeader'));
    });
};

/**
 * If menu will have a specific course preselected.
 */
var preload;
if(window.getQueryVariable("param") == false){
    RenderMenu();
}
<|endoftext|>


<commit_before>/**
 * @module ol/layer/Layer
 */
import {listen, unlistenByKey} from '../events.js';
import EventType from '../events/EventType.js';
import {getChangeEventType} from '../Object.js';
import BaseLayer from './Base.js';
import LayerProperty from './Property.js';
import {assign} from '../obj.js';
import RenderEventType from '../render/EventType.js';
import SourceState from '../source/State.js';
import {assert} from '../asserts.js';

/**
 * @typedef {function(import("../PluggableMap.js").FrameState):HTMLElement} RenderFunction
 */

/**
 * @typedef {Object} Options
 * @property {string} [className='ol-layer'] A CSS class name to set to the layer element.
 * @property {number} [opacity=1] Opacity (0, 1).
 * @property {boolean} [visible=true] Visibility.
 * @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering.  The layer will not be
 * rendered outside of this extent.
 * @property {number} [zIndex] The z-index for layer rendering.  At rendering time, the layers
 * will be ordered, first by Z-index and then by position. When `undefined`, a `zIndex` of 0 is assumed
 * for layers that are added to the map's `layers` collection, or `Infinity` when the layer's `setMap()`
 * method was used.
 * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be
 * visible.
 * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
 * be visible.
 * @property {import("../source/Source.js").default} [source] Source for this layer.  If not provided to the constructor,
 * the source can be set by calling {@link module:ol/layer/Layer#setSource layer.setSource(source)} after
 * construction.
 * @property {import("../PluggableMap.js").default} [map] Map.
 * @property {RenderFunction} [render] Render function. Takes the frame state as input and is expected to return an
 * HTML element. Will overwrite the default rendering for the layer.
 */

/**
 * @typedef {Object} State
 * @property {import("./Base.js").default} layer
 * @property {number} opacity Opacity, the value is rounded to two digits to appear after the decimal point.
 * @property {SourceState} sourceState
 * @property {boolean} visible
 * @property {boolean} managed
 * @property {import("../extent.js").Extent} [extent]
 * @property {number} zIndex
 * @property {number} maxResolution
 * @property {number} minResolution
 * @property {number} minZoom
 * @property {number} maxZoom
 */

/**
 * @classdesc
 * Base class from which all layer types are derived. This should only be instantiated
 * in the case where a custom layer is be added to the map with a custom `render` function.
 * Such a function can be specified in the `options` object, and is expected to return an HTML element.
 *
 * A visual representation of raster or vector map data.
 * Layers group together those properties that pertain to how the data is to be
 * displayed, irrespective of the source of that data.
 *
 * Layers are usually added to a map with {@link module:ol/Map#addLayer}. Components
 * like {@link module:ol/interaction/Select~Select} use unmanaged layers
 * internally. These unmanaged layers are associated with the map using
 * {@link module:ol/layer/Layer~Layer#setMap} instead.
 *
 * A generic `change` event is fired when the state of the source changes.
 *
 * Please note that for performance reasons several layers might get rendered to
 * the same HTML element, which will cause {@link module:ol/Map~Map#forEachLayerAtPixel} to
 * give false positives. To avoid this, apply different `className` properties to the
 * layers at creation time.
 *
 * @fires import("../render/Event.js").RenderEvent#prerender
 * @fires import("../render/Event.js").RenderEvent#postrender
 *
 * @template {import("../source/Source.js").default} SourceType
 * @api
 */
class Layer extends BaseLayer {
  /**
   * @param {Options} options Layer options.
   */
  constructor(options) {

    const baseOptions = assign({}, options);
    delete baseOptions.source;

    super(baseOptions);

    /**
     * @private
     * @type {?import("../events.js").EventsKey}
     */
    this.mapPrecomposeKey_ = null;

    /**
     * @private
     * @type {?import("../events.js").EventsKey}
     */
    this.mapRenderKey_ = null;

    /**
     * @private
     * @type {?import("../events.js").EventsKey}
     */
    this.sourceChangeKey_ = null;

    /**
     * @private
     * @type {import("../renderer/Layer.js").default}
     */
    this.renderer_ = null;

    // Overwrite default render method with a custom one
    if (options.render) {
      this.render = options.render;
    }

    if (options.map) {
      this.setMap(options.map);
    }

    this.addEventListener(getChangeEventType(LayerProperty.SOURCE), this.handleSourcePropertyChange_);

    const source = options.source ? /** @type {SourceType} */ (options.source) : null;
    this.setSource(source);
  }

  /**
   * @inheritDoc
   */
  getLayersArray(opt_array) {
    const array = opt_array ? opt_array : [];
    array.push(this);
    return array;
  }

  /**
   * @inheritDoc
   */
  getLayerStatesArray(opt_states) {
    const states = opt_states ? opt_states : [];
    states.push(this.getLayerState());
    return states;
  }

  /**
   * Get the layer source.
   * @return {SourceType} The layer source (or `null` if not yet set).
   * @observable
   * @api
   */
  getSource() {
    return /** @type {SourceType} */ (this.get(LayerProperty.SOURCE)) || null;
  }

  /**
    * @inheritDoc
    */
  getSourceState() {
    const source = this.getSource();
    return !source ? SourceState.UNDEFINED : source.getState();
  }

  /**
   * @private
   */
  handleSourceChange_() {
    this.changed();
  }

  /**
   * @private
   */
  handleSourcePropertyChange_() {
    if (this.sourceChangeKey_) {
      unlistenByKey(this.sourceChangeKey_);
      this.sourceChangeKey_ = null;
    }
    const source = this.getSource();
    if (source) {
      this.sourceChangeKey_ = listen(source,
        EventType.CHANGE, this.handleSourceChange_, this);
    }
    this.changed();
  }

  /**
   * @param {import("../pixel").Pixel} pixel Pixel.
   * @return {Promise<Array<import("../Feature").default>>} Promise that resolves with
   * an array of features.
   */
  getFeatures(pixel) {
    return this.renderer_.getFeatures(pixel);
  }

  /**
   * In charge to manage the rendering of the layer. One layer type is
   * bounded with one layer renderer.
   * @param {?import("../PluggableMap.js").FrameState} frameState Frame state.
   * @param {HTMLElement} target Target which the renderer may (but need not) use
   * for rendering its content.
   * @return {HTMLElement} The rendered element.
   */
  render(frameState, target) {
    const layerRenderer = this.getRenderer();

    if (layerRenderer.prepareFrame(frameState)) {
      return layerRenderer.renderFrame(frameState, target);
    }
  }

  /**
   * Sets the layer to be rendered on top of other layers on a map. The map will
   * not manage this layer in its layers collection, and the callback in
   * {@link module:ol/Map#forEachLayerAtPixel} will receive `null` as layer. This
   * is useful for temporary layers. To remove an unmanaged layer from the map,
   * use `#setMap(null)`.
   *
   * To add the layer to a map and have it managed by the map, use
   * {@link module:ol/Map#addLayer} instead.
   * @param {import("../PluggableMap.js").default} map Map.
   * @api
   */
  setMap(map) {
    if (this.mapPrecomposeKey_) {
      unlistenByKey(this.mapPrecomposeKey_);
      this.mapPrecomposeKey_ = null;
    }
    if (!map) {
      this.changed();
    }
    if (this.mapRenderKey_) {
      unlistenByKey(this.mapRenderKey_);
      this.mapRenderKey_ = null;
    }
    if (map) {
      this.mapPrecomposeKey_ = listen(map, RenderEventType.PRECOMPOSE, function(evt) {
        const renderEvent = /** @type {import("../render/Event.js").default} */ (evt);
        const layerStatesArray = renderEvent.frameState.layerStatesArray;
        const layerState = this.getLayerState(false);
        // A layer can only be added to the map once. Use either `layer.setMap()` or `map.addLayer()`, not both.
        assert(!layerStatesArray.some(function(arrayLayerState) {
          return arrayLayerState.layer === layerState.layer;
        }), 67);
        layerStatesArray.push(layerState);
      }, this);
      this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map);
      this.changed();
    }
  }

  /**
   * Set the layer source.
   * @param {SourceType} source The layer source.
   * @observable
   * @api
   */
  setSource(source) {
    this.set(LayerProperty.SOURCE, source);
  }

  /**
   * Get the renderer for this layer.
   * @return {import("../renderer/Layer.js").default} The layer renderer.
   */
  getRenderer() {
    if (!this.renderer_) {
      this.renderer_ = this.createRenderer();
    }
    return this.renderer_;
  }

  /**
   * @return {boolean} The layer has a renderer.
   */
  hasRenderer() {
    return !!this.renderer_;
  }

  /**
   * Create a renderer for this layer.
   * @return {import("../renderer/Layer.js").default} A layer renderer.
   * @protected
   */
  createRenderer() {
    return null;
  }

  /**
   * @inheritDoc
   */
  disposeInternal() {
    this.setSource(null);
    super.disposeInternal();
  }
}

/**
 * Return `true` if the layer is visible and if the provided view state
 * has resolution and zoom levels that are in range of the layer's min/max.
 * @param {State} layerState Layer state.
 * @param {import("../View.js").State} viewState View state.
 * @return {boolean} The layer is visible at the given view state.
 */
export function inView(layerState, viewState) {
  if (!layerState.visible) {
    return false;
  }
  const resolution = viewState.resolution;
  if (resolution < layerState.minResolution || resolution >= layerState.maxResolution) {
    return false;
  }
  const zoom = viewState.zoom;
  return zoom > layerState.minZoom && zoom <= layerState.maxZoom;
}

export default Layer;
<commit_msg>add minZoom and maxZoom options<commit_after>/**
 * @module ol/layer/Layer
 */
import {listen, unlistenByKey} from '../events.js';
import EventType from '../events/EventType.js';
import {getChangeEventType} from '../Object.js';
import BaseLayer from './Base.js';
import LayerProperty from './Property.js';
import {assign} from '../obj.js';
import RenderEventType from '../render/EventType.js';
import SourceState from '../source/State.js';
import {assert} from '../asserts.js';

/**
 * @typedef {function(import("../PluggableMap.js").FrameState):HTMLElement} RenderFunction
 */

/**
 * @typedef {Object} Options
 * @property {string} [className='ol-layer'] A CSS class name to set to the layer element.
 * @property {number} [opacity=1] Opacity (0, 1).
 * @property {boolean} [visible=true] Visibility.
 * @property {import("../extent.js").Extent} [extent] The bounding extent for layer rendering.  The layer will not be
 * rendered outside of this extent.
 * @property {number} [zIndex] The z-index for layer rendering.  At rendering time, the layers
 * will be ordered, first by Z-index and then by position. When `undefined`, a `zIndex` of 0 is assumed
 * for layers that are added to the map's `layers` collection, or `Infinity` when the layer's `setMap()`
 * method was used.
 * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be
 * visible.
 * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
 * be visible.
 * @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
 * visible.
 * @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
 * be visible.
 * @property {import("../source/Source.js").default} [source] Source for this layer.  If not provided to the constructor,
 * the source can be set by calling {@link module:ol/layer/Layer#setSource layer.setSource(source)} after
 * construction.
 * @property {import("../PluggableMap.js").default} [map] Map.
 * @property {RenderFunction} [render] Render function. Takes the frame state as input and is expected to return an
 * HTML element. Will overwrite the default rendering for the layer.
 */

/**
 * @typedef {Object} State
 * @property {import("./Base.js").default} layer
 * @property {number} opacity Opacity, the value is rounded to two digits to appear after the decimal point.
 * @property {SourceState} sourceState
 * @property {boolean} visible
 * @property {boolean} managed
 * @property {import("../extent.js").Extent} [extent]
 * @property {number} zIndex
 * @property {number} maxResolution
 * @property {number} minResolution
 * @property {number} minZoom
 * @property {number} maxZoom
 */

/**
 * @classdesc
 * Base class from which all layer types are derived. This should only be instantiated
 * in the case where a custom layer is be added to the map with a custom `render` function.
 * Such a function can be specified in the `options` object, and is expected to return an HTML element.
 *
 * A visual representation of raster or vector map data.
 * Layers group together those properties that pertain to how the data is to be
 * displayed, irrespective of the source of that data.
 *
 * Layers are usually added to a map with {@link module:ol/Map#addLayer}. Components
 * like {@link module:ol/interaction/Select~Select} use unmanaged layers
 * internally. These unmanaged layers are associated with the map using
 * {@link module:ol/layer/Layer~Layer#setMap} instead.
 *
 * A generic `change` event is fired when the state of the source changes.
 *
 * Please note that for performance reasons several layers might get rendered to
 * the same HTML element, which will cause {@link module:ol/Map~Map#forEachLayerAtPixel} to
 * give false positives. To avoid this, apply different `className` properties to the
 * layers at creation time.
 *
 * @fires import("../render/Event.js").RenderEvent#prerender
 * @fires import("../render/Event.js").RenderEvent#postrender
 *
 * @template {import("../source/Source.js").default} SourceType
 * @api
 */
class Layer extends BaseLayer {
  /**
   * @param {Options} options Layer options.
   */
  constructor(options) {

    const baseOptions = assign({}, options);
    delete baseOptions.source;

    super(baseOptions);

    /**
     * @private
     * @type {?import("../events.js").EventsKey}
     */
    this.mapPrecomposeKey_ = null;

    /**
     * @private
     * @type {?import("../events.js").EventsKey}
     */
    this.mapRenderKey_ = null;

    /**
     * @private
     * @type {?import("../events.js").EventsKey}
     */
    this.sourceChangeKey_ = null;

    /**
     * @private
     * @type {import("../renderer/Layer.js").default}
     */
    this.renderer_ = null;

    // Overwrite default render method with a custom one
    if (options.render) {
      this.render = options.render;
    }

    if (options.map) {
      this.setMap(options.map);
    }

    this.addEventListener(getChangeEventType(LayerProperty.SOURCE), this.handleSourcePropertyChange_);

    const source = options.source ? /** @type {SourceType} */ (options.source) : null;
    this.setSource(source);
  }

  /**
   * @inheritDoc
   */
  getLayersArray(opt_array) {
    const array = opt_array ? opt_array : [];
    array.push(this);
    return array;
  }

  /**
   * @inheritDoc
   */
  getLayerStatesArray(opt_states) {
    const states = opt_states ? opt_states : [];
    states.push(this.getLayerState());
    return states;
  }

  /**
   * Get the layer source.
   * @return {SourceType} The layer source (or `null` if not yet set).
   * @observable
   * @api
   */
  getSource() {
    return /** @type {SourceType} */ (this.get(LayerProperty.SOURCE)) || null;
  }

  /**
    * @inheritDoc
    */
  getSourceState() {
    const source = this.getSource();
    return !source ? SourceState.UNDEFINED : source.getState();
  }

  /**
   * @private
   */
  handleSourceChange_() {
    this.changed();
  }

  /**
   * @private
   */
  handleSourcePropertyChange_() {
    if (this.sourceChangeKey_) {
      unlistenByKey(this.sourceChangeKey_);
      this.sourceChangeKey_ = null;
    }
    const source = this.getSource();
    if (source) {
      this.sourceChangeKey_ = listen(source,
        EventType.CHANGE, this.handleSourceChange_, this);
    }
    this.changed();
  }

  /**
   * @param {import("../pixel").Pixel} pixel Pixel.
   * @return {Promise<Array<import("../Feature").default>>} Promise that resolves with
   * an array of features.
   */
  getFeatures(pixel) {
    return this.renderer_.getFeatures(pixel);
  }

  /**
   * In charge to manage the rendering of the layer. One layer type is
   * bounded with one layer renderer.
   * @param {?import("../PluggableMap.js").FrameState} frameState Frame state.
   * @param {HTMLElement} target Target which the renderer may (but need not) use
   * for rendering its content.
   * @return {HTMLElement} The rendered element.
   */
  render(frameState, target) {
    const layerRenderer = this.getRenderer();

    if (layerRenderer.prepareFrame(frameState)) {
      return layerRenderer.renderFrame(frameState, target);
    }
  }

  /**
   * Sets the layer to be rendered on top of other layers on a map. The map will
   * not manage this layer in its layers collection, and the callback in
   * {@link module:ol/Map#forEachLayerAtPixel} will receive `null` as layer. This
   * is useful for temporary layers. To remove an unmanaged layer from the map,
   * use `#setMap(null)`.
   *
   * To add the layer to a map and have it managed by the map, use
   * {@link module:ol/Map#addLayer} instead.
   * @param {import("../PluggableMap.js").default} map Map.
   * @api
   */
  setMap(map) {
    if (this.mapPrecomposeKey_) {
      unlistenByKey(this.mapPrecomposeKey_);
      this.mapPrecomposeKey_ = null;
    }
    if (!map) {
      this.changed();
    }
    if (this.mapRenderKey_) {
      unlistenByKey(this.mapRenderKey_);
      this.mapRenderKey_ = null;
    }
    if (map) {
      this.mapPrecomposeKey_ = listen(map, RenderEventType.PRECOMPOSE, function(evt) {
        const renderEvent = /** @type {import("../render/Event.js").default} */ (evt);
        const layerStatesArray = renderEvent.frameState.layerStatesArray;
        const layerState = this.getLayerState(false);
        // A layer can only be added to the map once. Use either `layer.setMap()` or `map.addLayer()`, not both.
        assert(!layerStatesArray.some(function(arrayLayerState) {
          return arrayLayerState.layer === layerState.layer;
        }), 67);
        layerStatesArray.push(layerState);
      }, this);
      this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map);
      this.changed();
    }
  }

  /**
   * Set the layer source.
   * @param {SourceType} source The layer source.
   * @observable
   * @api
   */
  setSource(source) {
    this.set(LayerProperty.SOURCE, source);
  }

  /**
   * Get the renderer for this layer.
   * @return {import("../renderer/Layer.js").default} The layer renderer.
   */
  getRenderer() {
    if (!this.renderer_) {
      this.renderer_ = this.createRenderer();
    }
    return this.renderer_;
  }

  /**
   * @return {boolean} The layer has a renderer.
   */
  hasRenderer() {
    return !!this.renderer_;
  }

  /**
   * Create a renderer for this layer.
   * @return {import("../renderer/Layer.js").default} A layer renderer.
   * @protected
   */
  createRenderer() {
    return null;
  }

  /**
   * @inheritDoc
   */
  disposeInternal() {
    this.setSource(null);
    super.disposeInternal();
  }
}

/**
 * Return `true` if the layer is visible and if the provided view state
 * has resolution and zoom levels that are in range of the layer's min/max.
 * @param {State} layerState Layer state.
 * @param {import("../View.js").State} viewState View state.
 * @return {boolean} The layer is visible at the given view state.
 */
export function inView(layerState, viewState) {
  if (!layerState.visible) {
    return false;
  }
  const resolution = viewState.resolution;
  if (resolution < layerState.minResolution || resolution >= layerState.maxResolution) {
    return false;
  }
  const zoom = viewState.zoom;
  return zoom > layerState.minZoom && zoom <= layerState.maxZoom;
}

export default Layer;
<|endoftext|>


<commit_before>goog.provide('ol.layer.Group');

goog.require('ol');
goog.require('ol.asserts');
goog.require('ol.Collection');
goog.require('ol.CollectionEventType');
goog.require('ol.Object');
goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol.extent');
goog.require('ol.layer.Base');
goog.require('ol.obj');
goog.require('ol.source.State');

/**
 * @classdesc
 * A {@link ol.Collection} of layers that are handled together.
 *
 * A generic `change` event is triggered when the group/Collection changes.
 *
 * @constructor
 * @extends {ol.layer.Base}
 * @param {olx.layer.GroupOptions=} opt_options Layer options.
 * @api stable
 */
ol.layer.Group = function(opt_options) {

  var options = opt_options || {};
  var baseOptions = /** @type {olx.layer.GroupOptions} */
      (ol.obj.assign({}, options));
  delete baseOptions.layers;

  var layers = options.layers;

  ol.layer.Base.call(this, baseOptions);

  /**
   * @private
   * @type {Array.<ol.EventsKey>}
   */
  this.layersListenerKeys_ = [];

  /**
   * @private
   * @type {Object.<string, Array.<ol.EventsKey>>}
   */
  this.listenerKeys_ = {};

  ol.events.listen(this,
      ol.Object.getChangeEventType(ol.layer.Group.Property.LAYERS),
      this.handleLayersChanged_, this);

  if (layers) {
    if (Array.isArray(layers)) {
      layers = new ol.Collection(layers.slice());
    } else {
      ol.asserts.assert(layers instanceof ol.Collection,
          43); // Expected `layers` to be an array or an `ol.Collection`
      layers = layers;
    }
  } else {
    layers = new ol.Collection();
  }

  this.setLayers(layers);

};
ol.inherits(ol.layer.Group, ol.layer.Base);

/**
 * @private
 */
ol.layer.Group.prototype.handleLayerChange_ = function() {
  if (this.getVisible()) {
    this.changed();
  }
};

/**
 * @param {ol.events.Event} event Event.
 * @private
 */
ol.layer.Group.prototype.handleLayersChanged_ = function(event) {
  this.layersListenerKeys_.forEach(ol.events.unlistenByKey);
  this.layersListenerKeys_.length = 0;

  var layers = this.getLayers();
  this.layersListenerKeys_.push(
      ol.events.listen(layers, ol.CollectionEventType.ADD,
          this.handleLayersAdd_, this),
      ol.events.listen(layers, ol.CollectionEventType.REMOVE,
          this.handleLayersRemove_, this));

  for (var id in this.listenerKeys_) {
    this.listenerKeys_[id].forEach(ol.events.unlistenByKey);
  }
  ol.obj.clear(this.listenerKeys_);

  var layersArray = layers.getArray();
  var i, ii, layer;
  for (i = 0, ii = layersArray.length; i < ii; i++) {
    layer = layersArray[i];
    this.listenerKeys_[ol.getUid(layer).toString()] = [
      ol.events.listen(layer, ol.Object.EventType.PROPERTYCHANGE,
          this.handleLayerChange_, this),
      ol.events.listen(layer, ol.events.EventType.CHANGE,
          this.handleLayerChange_, this)
    ];
  }

  this.changed();
};

/**
 * @param {ol.Collection.Event} collectionEvent Collection event.
 * @private
 */
ol.layer.Group.prototype.handleLayersAdd_ = function(collectionEvent) {
  var layer = /** @type {ol.layer.Base} */ (collectionEvent.element);
  var key = ol.getUid(layer).toString();
  ol.DEBUG && console.assert(!(key in this.listenerKeys_),
      'listeners already registered');
  this.listenerKeys_[key] = [
    ol.events.listen(layer, ol.Object.EventType.PROPERTYCHANGE,
        this.handleLayerChange_, this),
    ol.events.listen(layer, ol.events.EventType.CHANGE,
        this.handleLayerChange_, this)
  ];
  this.changed();
};

/**
 * @param {ol.Collection.Event} collectionEvent Collection event.
 * @private
 */
ol.layer.Group.prototype.handleLayersRemove_ = function(collectionEvent) {
  var layer = /** @type {ol.layer.Base} */ (collectionEvent.element);
  var key = ol.getUid(layer).toString();
  ol.DEBUG && console.assert(key in this.listenerKeys_, 'no listeners to unregister');
  this.listenerKeys_[key].forEach(ol.events.unlistenByKey);
  delete this.listenerKeys_[key];
  this.changed();
};

/**
 * Returns the {@link ol.Collection collection} of {@link ol.layer.Layer layers}
 * in this group.
 * @return {!ol.Collection.<ol.layer.Base>} Collection of
 *   {@link ol.layer.Base layers} that are part of this group.
 * @observable
 * @api stable
 */
ol.layer.Group.prototype.getLayers = function() {
  return /** @type {!ol.Collection.<ol.layer.Base>} */ (this.get(
      ol.layer.Group.Property.LAYERS));
};

/**
 * Set the {@link ol.Collection collection} of {@link ol.layer.Layer layers}
 * in this group.
 * @param {!ol.Collection.<ol.layer.Base>} layers Collection of
 *   {@link ol.layer.Base layers} that are part of this group.
 * @observable
 * @api stable
 */
ol.layer.Group.prototype.setLayers = function(layers) {
  this.set(ol.layer.Group.Property.LAYERS, layers);
};

/**
 * @inheritDoc
 */
ol.layer.Group.prototype.getLayersArray = function(opt_array) {
  var array = opt_array !== undefined ? opt_array : [];
  this.getLayers().forEach(function(layer) {
    layer.getLayersArray(array);
  });
  return array;
};

/**
 * @inheritDoc
 */
ol.layer.Group.prototype.getLayerStatesArray = function(opt_states) {
  var states = opt_states !== undefined ? opt_states : [];

  var pos = states.length;

  this.getLayers().forEach(function(layer) {
    layer.getLayerStatesArray(states);
  });

  var ownLayerState = this.getLayerState();
  var i, ii, layerState;
  for (i = pos, ii = states.length; i < ii; i++) {
    layerState = states[i];
    layerState.opacity *= ownLayerState.opacity;
    layerState.visible = layerState.visible && ownLayerState.visible;
    layerState.maxResolution = Math.min(
        layerState.maxResolution, ownLayerState.maxResolution);
    layerState.minResolution = Math.max(
        layerState.minResolution, ownLayerState.minResolution);
    if (ownLayerState.extent !== undefined) {
      if (layerState.extent !== undefined) {
        layerState.extent = ol.extent.getIntersection(
            layerState.extent, ownLayerState.extent);
      } else {
        layerState.extent = ownLayerState.extent;
      }
    }
  }

  return states;
};

/**
 * @inheritDoc
 */
ol.layer.Group.prototype.getSourceState = function() {
  return ol.source.State.READY;
};

/**
 * @enum {string}
 */
ol.layer.Group.Property = {
  LAYERS: 'layers'
};
<commit_msg>Private enum for layer group properties<commit_after>goog.provide('ol.layer.Group');

goog.require('ol');
goog.require('ol.asserts');
goog.require('ol.Collection');
goog.require('ol.CollectionEventType');
goog.require('ol.Object');
goog.require('ol.events');
goog.require('ol.events.EventType');
goog.require('ol.extent');
goog.require('ol.layer.Base');
goog.require('ol.obj');
goog.require('ol.source.State');

/**
 * @classdesc
 * A {@link ol.Collection} of layers that are handled together.
 *
 * A generic `change` event is triggered when the group/Collection changes.
 *
 * @constructor
 * @extends {ol.layer.Base}
 * @param {olx.layer.GroupOptions=} opt_options Layer options.
 * @api stable
 */
ol.layer.Group = function(opt_options) {

  var options = opt_options || {};
  var baseOptions = /** @type {olx.layer.GroupOptions} */
      (ol.obj.assign({}, options));
  delete baseOptions.layers;

  var layers = options.layers;

  ol.layer.Base.call(this, baseOptions);

  /**
   * @private
   * @type {Array.<ol.EventsKey>}
   */
  this.layersListenerKeys_ = [];

  /**
   * @private
   * @type {Object.<string, Array.<ol.EventsKey>>}
   */
  this.listenerKeys_ = {};

  ol.events.listen(this,
      ol.Object.getChangeEventType(ol.layer.Group.Property_.LAYERS),
      this.handleLayersChanged_, this);

  if (layers) {
    if (Array.isArray(layers)) {
      layers = new ol.Collection(layers.slice());
    } else {
      ol.asserts.assert(layers instanceof ol.Collection,
          43); // Expected `layers` to be an array or an `ol.Collection`
      layers = layers;
    }
  } else {
    layers = new ol.Collection();
  }

  this.setLayers(layers);

};
ol.inherits(ol.layer.Group, ol.layer.Base);

/**
 * @private
 */
ol.layer.Group.prototype.handleLayerChange_ = function() {
  if (this.getVisible()) {
    this.changed();
  }
};

/**
 * @param {ol.events.Event} event Event.
 * @private
 */
ol.layer.Group.prototype.handleLayersChanged_ = function(event) {
  this.layersListenerKeys_.forEach(ol.events.unlistenByKey);
  this.layersListenerKeys_.length = 0;

  var layers = this.getLayers();
  this.layersListenerKeys_.push(
      ol.events.listen(layers, ol.CollectionEventType.ADD,
          this.handleLayersAdd_, this),
      ol.events.listen(layers, ol.CollectionEventType.REMOVE,
          this.handleLayersRemove_, this));

  for (var id in this.listenerKeys_) {
    this.listenerKeys_[id].forEach(ol.events.unlistenByKey);
  }
  ol.obj.clear(this.listenerKeys_);

  var layersArray = layers.getArray();
  var i, ii, layer;
  for (i = 0, ii = layersArray.length; i < ii; i++) {
    layer = layersArray[i];
    this.listenerKeys_[ol.getUid(layer).toString()] = [
      ol.events.listen(layer, ol.Object.EventType.PROPERTYCHANGE,
          this.handleLayerChange_, this),
      ol.events.listen(layer, ol.events.EventType.CHANGE,
          this.handleLayerChange_, this)
    ];
  }

  this.changed();
};

/**
 * @param {ol.Collection.Event} collectionEvent Collection event.
 * @private
 */
ol.layer.Group.prototype.handleLayersAdd_ = function(collectionEvent) {
  var layer = /** @type {ol.layer.Base} */ (collectionEvent.element);
  var key = ol.getUid(layer).toString();
  ol.DEBUG && console.assert(!(key in this.listenerKeys_),
      'listeners already registered');
  this.listenerKeys_[key] = [
    ol.events.listen(layer, ol.Object.EventType.PROPERTYCHANGE,
        this.handleLayerChange_, this),
    ol.events.listen(layer, ol.events.EventType.CHANGE,
        this.handleLayerChange_, this)
  ];
  this.changed();
};

/**
 * @param {ol.Collection.Event} collectionEvent Collection event.
 * @private
 */
ol.layer.Group.prototype.handleLayersRemove_ = function(collectionEvent) {
  var layer = /** @type {ol.layer.Base} */ (collectionEvent.element);
  var key = ol.getUid(layer).toString();
  ol.DEBUG && console.assert(key in this.listenerKeys_, 'no listeners to unregister');
  this.listenerKeys_[key].forEach(ol.events.unlistenByKey);
  delete this.listenerKeys_[key];
  this.changed();
};

/**
 * Returns the {@link ol.Collection collection} of {@link ol.layer.Layer layers}
 * in this group.
 * @return {!ol.Collection.<ol.layer.Base>} Collection of
 *   {@link ol.layer.Base layers} that are part of this group.
 * @observable
 * @api stable
 */
ol.layer.Group.prototype.getLayers = function() {
  return /** @type {!ol.Collection.<ol.layer.Base>} */ (this.get(
      ol.layer.Group.Property_.LAYERS));
};

/**
 * Set the {@link ol.Collection collection} of {@link ol.layer.Layer layers}
 * in this group.
 * @param {!ol.Collection.<ol.layer.Base>} layers Collection of
 *   {@link ol.layer.Base layers} that are part of this group.
 * @observable
 * @api stable
 */
ol.layer.Group.prototype.setLayers = function(layers) {
  this.set(ol.layer.Group.Property_.LAYERS, layers);
};

/**
 * @inheritDoc
 */
ol.layer.Group.prototype.getLayersArray = function(opt_array) {
  var array = opt_array !== undefined ? opt_array : [];
  this.getLayers().forEach(function(layer) {
    layer.getLayersArray(array);
  });
  return array;
};

/**
 * @inheritDoc
 */
ol.layer.Group.prototype.getLayerStatesArray = function(opt_states) {
  var states = opt_states !== undefined ? opt_states : [];

  var pos = states.length;

  this.getLayers().forEach(function(layer) {
    layer.getLayerStatesArray(states);
  });

  var ownLayerState = this.getLayerState();
  var i, ii, layerState;
  for (i = pos, ii = states.length; i < ii; i++) {
    layerState = states[i];
    layerState.opacity *= ownLayerState.opacity;
    layerState.visible = layerState.visible && ownLayerState.visible;
    layerState.maxResolution = Math.min(
        layerState.maxResolution, ownLayerState.maxResolution);
    layerState.minResolution = Math.max(
        layerState.minResolution, ownLayerState.minResolution);
    if (ownLayerState.extent !== undefined) {
      if (layerState.extent !== undefined) {
        layerState.extent = ol.extent.getIntersection(
            layerState.extent, ownLayerState.extent);
      } else {
        layerState.extent = ownLayerState.extent;
      }
    }
  }

  return states;
};

/**
 * @inheritDoc
 */
ol.layer.Group.prototype.getSourceState = function() {
  return ol.source.State.READY;
};

/**
 * @enum {string}
 * @private
 */
ol.layer.Group.Property_ = {
  LAYERS: 'layers'
};
<|endoftext|>


<commit_before>import 'core-js/fn/object/values' // shim Object.values for Chromium<54
import { createStore, applyMiddleware, compose, combineReducers } from 'redux'
import { createEpicMiddleware, combineEpics } from 'redux-observable'
import Raven from 'raven-js'
import createRavenMiddleware from 'raven-for-redux'
import thunk from 'redux-thunk'

import overview from 'src/overview'
import { reducer as onboarding } from 'src/overview/onboarding'
import { reducer as filters } from 'src/overview/filters'

const rootReducer = combineReducers({
    overview: overview.reducer,
    onboarding,
    filters,
})

const rootEpic = combineEpics(...Object.values(overview.epics))

export default function configureStore({ ReduxDevTools = undefined } = {}) {
    const middlewares = [createEpicMiddleware(rootEpic), thunk]

    // Set up the sentry runtime error config + redux middleware
    if (process.env.SENTRY_DSN) {
        Raven.config(process.env.SENTRY_DSN).install()
        middlewares.push(createRavenMiddleware(Raven))
    }

    const enhancers = [overview.enhancer, applyMiddleware(...middlewares)]
    if (ReduxDevTools) {
        enhancers.push(ReduxDevTools.instrument())
    }
    const enhancer = compose(...enhancers)

    const store = createStore(
        rootReducer,
        undefined, // initial state
        enhancer,
    )

    return store
}
<commit_msg>Add filter to remove parts for sentry-recorded UI state<commit_after>import 'core-js/fn/object/values' // shim Object.values for Chromium<54
import { createStore, applyMiddleware, compose, combineReducers } from 'redux'
import { createEpicMiddleware, combineEpics } from 'redux-observable'
import Raven from 'raven-js'
import createRavenMiddleware from 'raven-for-redux'
import thunk from 'redux-thunk'

import overview from 'src/overview'
import { reducer as onboarding } from 'src/overview/onboarding'
import { reducer as filters } from 'src/overview/filters'

const rootReducer = combineReducers({
    overview: overview.reducer,
    onboarding,
    filters,
})

const rootEpic = combineEpics(...Object.values(overview.epics))

/**
 * Used to transform the redux state before sending to raven, filtering out
 * anything we don't need to know.
 */
const stateTransformer = ({ overview, ...state }) => ({
    ...state,
    overview: {
        ...overview,
        searchResult: {
            ...overview.searchResult,
            // Filter out personal stuff from results; not really useful for our knowledge
            docs: overview.searchResult.docs.map(
                ({ url, title, favIcon, screenshot, ...doc }) => doc,
            ),
        },
    },
})

export default function configureStore({ ReduxDevTools = undefined } = {}) {
    const middlewares = [createEpicMiddleware(rootEpic), thunk]

    // Set up the sentry runtime error config + redux middleware
    if (process.env.SENTRY_DSN) {
        Raven.config(process.env.SENTRY_DSN).install()
        middlewares.push(createRavenMiddleware(Raven, { stateTransformer }))
    }

    const enhancers = [overview.enhancer, applyMiddleware(...middlewares)]
    if (ReduxDevTools) {
        enhancers.push(ReduxDevTools.instrument())
    }
    const enhancer = compose(...enhancers)

    const store = createStore(
        rootReducer,
        undefined, // initial state
        enhancer,
    )

    return store
}
<|endoftext|>


<commit_before>import React from 'react'
import { useStaticQuery, graphql } from 'gatsby'
import Helmet from 'react-helmet'
import system from 'system-components'
import Header from '../components/Header'
import { Flex } from '../components/Primitives'
import { Title } from '../components/Typography'
import { themeHover } from '../utils/styles'
import { dependencies } from '../../package-lock.json'

const Section = system(
  {
    is: 'section',
  },
  'space'
)

const SectionTitle = system({
  is: 'h2',
  fontSize: [3, 4],
  my: 0,
})

const Dep = system({
  is: 'p',
  display: 'flex',
  alignItems: 'center',
  mt: 3,
  mb: 0,
})

const DepLink = system(
  {
    is: 'a',
    fontSize: [2, 3],
    fontWeight: 6,
  },
  themeHover
)

const DepVer = system({
  is: 'span',
  fontFamily: 'monospace',
  ml: 3,
})

const SanityCheck = system({
  is: 'p',
  mt: 3,
  mb: 0,
  fontSize: [2, 3],
  fontWeight: 6,
})

const ColophonPage = () => {
  const data = useStaticQuery(graphql`
    query ColophonQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)

  const {
    react: { version: react },
    gatsby: { version: gatsby },
    'react-helmet': { version: helmet },
    'sanitize.css': { version: sanitize },
    'styled-components': { version: styledComponents },
    'system-components': { version: systemComponents },
    eslint: { version: eslint },
    prettier: { version: prettier },
  } = dependencies

  return (
    <>
      <Helmet>
        <title>Colophon • {data.site.siteMetadata.title}</title>
      </Helmet>

          <Title>Building Blocks</Title>

        <Flex is="main" flexDirection={['column', 'column', 'row']}>

            <SectionTitle>Functionality</SectionTitle>

            <Dep mt={4}>
              <DepLink href="https://reactjs.org">React</DepLink>{' '}
              <DepVer>{react}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://gatsbyjs.org">Gatsby</DepLink>{' '}
              <DepVer>{gatsby}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://github.com/nfl/react-helmet">
                React Helmet
              </DepLink>{' '}
              <DepVer>{helmet}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://csstools.github.io/sanitize.css/">
                sanitize.css
              </DepLink>{' '}
              <DepVer>{sanitize}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://styled-components.com/">
                styled-components
              </DepLink>{' '}
              <DepVer>{styledComponents}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://github.com/jxnblk/styled-system/tree/master/system-components">
                system-components
              </DepLink>{' '}
              <DepVer>{systemComponents}</DepVer>
            </Dep>

            <SectionTitle>Infrastructure</SectionTitle>

            <Dep mt={4}>
              <DepLink href="https://netlify.com">Netlify</DepLink>
            </Dep>

            <Dep>
              <DepLink href="https://github.com">GitHub</DepLink>
            </Dep>

            <Dep>
              <DepLink href="https://get.gaug.es">Gauges</DepLink>
            </Dep>

            <Dep>
              <DepLink href="https://eslint.org/">ESLint</DepLink>{' '}
              <DepVer>{eslint}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://prettier.io/">Prettier</DepLink>{' '}
              <DepVer>{prettier}</DepVer>
            </Dep>

            <SectionTitle>Sanity</SectionTitle>

            <SanityCheck mt={4}>Music</SanityCheck>

            <SanityCheck>Coffee</SanityCheck>

            <SanityCheck>Beer</SanityCheck>

            <SanityCheck>Burritos</SanityCheck>

            <SanityCheck>Skateboarding</SanityCheck>

            <SanityCheck>Basketball</SanityCheck>

        </Flex>

    </>
  )
}

export default ColophonPage
<commit_msg>:lipstick: align colophon dependency versions to baseline<commit_after>import React from 'react'
import { useStaticQuery, graphql } from 'gatsby'
import Helmet from 'react-helmet'
import system from 'system-components'
import Header from '../components/Header'
import { Flex } from '../components/Primitives'
import { Title } from '../components/Typography'
import { themeHover } from '../utils/styles'
import { dependencies } from '../../package-lock.json'

const Section = system(
  {
    is: 'section',
  },
  'space'
)

const SectionTitle = system({
  is: 'h2',
  fontSize: [3, 4],
  my: 0,
})

const Dep = system({
  is: 'p',
  display: 'flex',
  alignItems: 'baseline',
  mt: 3,
  mb: 0,
})

const DepLink = system(
  {
    is: 'a',
    fontSize: [2, 3],
    fontWeight: 6,
  },
  themeHover
)

const DepVer = system({
  is: 'span',
  fontFamily: 'monospace',
  ml: 3,
})

const SanityCheck = system({
  is: 'p',
  mt: 3,
  mb: 0,
  fontSize: [2, 3],
  fontWeight: 6,
})

const ColophonPage = () => {
  const data = useStaticQuery(graphql`
    query ColophonQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)

  const {
    react: { version: react },
    gatsby: { version: gatsby },
    'react-helmet': { version: helmet },
    'sanitize.css': { version: sanitize },
    'styled-components': { version: styledComponents },
    'system-components': { version: systemComponents },
    eslint: { version: eslint },
    prettier: { version: prettier },
  } = dependencies

  return (
    <>
      <Helmet>
        <title>Colophon • {data.site.siteMetadata.title}</title>
      </Helmet>

          <Title>Building Blocks</Title>

        <Flex is="main" flexDirection={['column', 'column', 'row']}>

            <SectionTitle>Functionality</SectionTitle>

            <Dep mt={4}>
              <DepLink href="https://reactjs.org">React</DepLink>{' '}
              <DepVer>{react}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://gatsbyjs.org">Gatsby</DepLink>{' '}
              <DepVer>{gatsby}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://github.com/nfl/react-helmet">
                React Helmet
              </DepLink>{' '}
              <DepVer>{helmet}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://csstools.github.io/sanitize.css/">
                sanitize.css
              </DepLink>{' '}
              <DepVer>{sanitize}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://styled-components.com/">
                styled-components
              </DepLink>{' '}
              <DepVer>{styledComponents}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://github.com/jxnblk/styled-system/tree/master/system-components">
                system-components
              </DepLink>{' '}
              <DepVer>{systemComponents}</DepVer>
            </Dep>

            <SectionTitle>Infrastructure</SectionTitle>

            <Dep mt={4}>
              <DepLink href="https://netlify.com">Netlify</DepLink>
            </Dep>

            <Dep>
              <DepLink href="https://github.com">GitHub</DepLink>
            </Dep>

            <Dep>
              <DepLink href="https://get.gaug.es">Gauges</DepLink>
            </Dep>

            <Dep>
              <DepLink href="https://eslint.org/">ESLint</DepLink>{' '}
              <DepVer>{eslint}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://prettier.io/">Prettier</DepLink>{' '}
              <DepVer>{prettier}</DepVer>
            </Dep>

            <SectionTitle>Sanity</SectionTitle>

            <SanityCheck mt={4}>Music</SanityCheck>

            <SanityCheck>Coffee</SanityCheck>

            <SanityCheck>Beer</SanityCheck>

            <SanityCheck>Burritos</SanityCheck>

            <SanityCheck>Skateboarding</SanityCheck>

            <SanityCheck>Basketball</SanityCheck>

        </Flex>

    </>
  )
}

export default ColophonPage
<|endoftext|>


<commit_before>import React from 'react'
import { useStaticQuery, graphql } from 'gatsby'
import Helmet from 'react-helmet'
import system from 'system-components'
import Header from '../components/Header'
import { Flex } from '../components/Primitives'
import { Title } from '../components/Typography'
import { themeHover } from '../utils/styles'
import { dependencies } from '../../package-lock.json'

const Section = system(
  {
    is: 'section',
  },
  'space'
)

const SectionTitle = system({
  is: 'h2',
  fontSize: [3, 4],
  my: 0,
})

const Dep = system({
  is: 'p',
  display: 'flex',
  alignItems: 'center',
  mt: 3,
  mb: 0,
})

const DepLink = system(
  {
    is: 'a',
    fontSize: [2, 3],
    fontWeight: 6,
  },
  themeHover
)

const DepVer = system({
  is: 'span',
  fontFamily: 'monospace',
  ml: 3,
})

const SanityCheck = system({
  is: 'p',
  mt: 3,
  mb: 0,
  fontSize: [2, 3],
  fontWeight: 6,
})

const ColophonPage = () => {
  const data = useStaticQuery(graphql`
    query ColophonQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)

  const {
    react: { version: react },
    gatsby: { version: gatsby },
    'react-helmet': { version: helmet },
    'sanitize.css': { version: sanitize },
    'styled-components': { version: styledComponents },
    'system-components': { version: systemComponents },
    eslint: { version: eslint },
    prettier: { version: prettier },
    husky: { version: husky },
    'lint-staged': { version: lintStaged },
  } = dependencies

  return (
    <>
      <Helmet>
        <title>Colophon • {data.site.siteMetadata.title}</title>
      </Helmet>

          <Title>Building Blocks</Title>

        <Flex is="main" flexDirection={['column', 'column', 'row']}>

            <SectionTitle>Functionality</SectionTitle>

            <Dep mt={4}>
              <DepLink href="https://reactjs.org">React</DepLink>{' '}
              <DepVer>{react}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://gatsbyjs.org">Gatsby</DepLink>{' '}
              <DepVer>{gatsby}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://github.com/nfl/react-helmet">
                React Helmet
              </DepLink>{' '}
              <DepVer>{helmet}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://csstools.github.io/sanitize.css/">
                sanitize.css
              </DepLink>{' '}
              <DepVer>{sanitize}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://styled-components.com/">
                styled-components
              </DepLink>{' '}
              <DepVer>{styledComponents}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://github.com/jxnblk/styled-system/tree/master/system-components">
                system-components
              </DepLink>{' '}
              <DepVer>{systemComponents}</DepVer>
            </Dep>

            <SectionTitle>Infrastructure</SectionTitle>

            <Dep mt={4}>
              <DepLink href="https://netlify.com">Netlify</DepLink>
            </Dep>

            <Dep>
              <DepLink href="https://github.com">GitHub</DepLink>
            </Dep>

            <Dep>
              <DepLink href="https://get.gaug.es">Gauges</DepLink>
            </Dep>

            <Dep>
              <DepLink href="https://eslint.org/">ESLint</DepLink>{' '}
              <DepVer>{eslint}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://prettier.io/">Prettier</DepLink>{' '}
              <DepVer>{prettier}</DepVer>
            </Dep>

            <SectionTitle>Sanity</SectionTitle>

            <SanityCheck mt={4}>Music</SanityCheck>

            <SanityCheck>Coffee</SanityCheck>

            <SanityCheck>Beer</SanityCheck>

            <SanityCheck>Burritos</SanityCheck>

            <SanityCheck>Skateboarding</SanityCheck>

            <SanityCheck>Basketball</SanityCheck>

        </Flex>

    </>
  )
}

export default ColophonPage
<commit_msg>:rotating_light: remove extra dependency version variables<commit_after>import React from 'react'
import { useStaticQuery, graphql } from 'gatsby'
import Helmet from 'react-helmet'
import system from 'system-components'
import Header from '../components/Header'
import { Flex } from '../components/Primitives'
import { Title } from '../components/Typography'
import { themeHover } from '../utils/styles'
import { dependencies } from '../../package-lock.json'

const Section = system(
  {
    is: 'section',
  },
  'space'
)

const SectionTitle = system({
  is: 'h2',
  fontSize: [3, 4],
  my: 0,
})

const Dep = system({
  is: 'p',
  display: 'flex',
  alignItems: 'center',
  mt: 3,
  mb: 0,
})

const DepLink = system(
  {
    is: 'a',
    fontSize: [2, 3],
    fontWeight: 6,
  },
  themeHover
)

const DepVer = system({
  is: 'span',
  fontFamily: 'monospace',
  ml: 3,
})

const SanityCheck = system({
  is: 'p',
  mt: 3,
  mb: 0,
  fontSize: [2, 3],
  fontWeight: 6,
})

const ColophonPage = () => {
  const data = useStaticQuery(graphql`
    query ColophonQuery {
      site {
        siteMetadata {
          title
        }
      }
    }
  `)

  const {
    react: { version: react },
    gatsby: { version: gatsby },
    'react-helmet': { version: helmet },
    'sanitize.css': { version: sanitize },
    'styled-components': { version: styledComponents },
    'system-components': { version: systemComponents },
    eslint: { version: eslint },
    prettier: { version: prettier },
  } = dependencies

  return (
    <>
      <Helmet>
        <title>Colophon • {data.site.siteMetadata.title}</title>
      </Helmet>

          <Title>Building Blocks</Title>

        <Flex is="main" flexDirection={['column', 'column', 'row']}>

            <SectionTitle>Functionality</SectionTitle>

            <Dep mt={4}>
              <DepLink href="https://reactjs.org">React</DepLink>{' '}
              <DepVer>{react}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://gatsbyjs.org">Gatsby</DepLink>{' '}
              <DepVer>{gatsby}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://github.com/nfl/react-helmet">
                React Helmet
              </DepLink>{' '}
              <DepVer>{helmet}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://csstools.github.io/sanitize.css/">
                sanitize.css
              </DepLink>{' '}
              <DepVer>{sanitize}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://styled-components.com/">
                styled-components
              </DepLink>{' '}
              <DepVer>{styledComponents}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://github.com/jxnblk/styled-system/tree/master/system-components">
                system-components
              </DepLink>{' '}
              <DepVer>{systemComponents}</DepVer>
            </Dep>

            <SectionTitle>Infrastructure</SectionTitle>

            <Dep mt={4}>
              <DepLink href="https://netlify.com">Netlify</DepLink>
            </Dep>

            <Dep>
              <DepLink href="https://github.com">GitHub</DepLink>
            </Dep>

            <Dep>
              <DepLink href="https://get.gaug.es">Gauges</DepLink>
            </Dep>

            <Dep>
              <DepLink href="https://eslint.org/">ESLint</DepLink>{' '}
              <DepVer>{eslint}</DepVer>
            </Dep>

            <Dep>
              <DepLink href="https://prettier.io/">Prettier</DepLink>{' '}
              <DepVer>{prettier}</DepVer>
            </Dep>

            <SectionTitle>Sanity</SectionTitle>

            <SanityCheck mt={4}>Music</SanityCheck>

            <SanityCheck>Coffee</SanityCheck>

            <SanityCheck>Beer</SanityCheck>

            <SanityCheck>Burritos</SanityCheck>

            <SanityCheck>Skateboarding</SanityCheck>

            <SanityCheck>Basketball</SanityCheck>

        </Flex>

    </>
  )
}

export default ColophonPage
<|endoftext|>


<commit_before>_gaq.push(['_trackPageview']);

// If awaiting activation
var waiting = true;

// If trusted exit, for exit confirmation
var trustedExit = false;

// If auto-focus on window to capture key events or not
var autoFocus = 0;

// Critical Animation
var critAnim = false;

// Show game screens
function ActivateGame(){
	waiting = false;
	$(".box-wrap").css("background", "#fff");
	$(".box-wait").hide();
	$(".game-swf").remove();
	$(".box-game")
		.prepend("")
		.find(".game-swf")
		.attr("src", localStorage.absoluteswf)
		.end()
		.show();
	return true;
}

$(document).on("ready", function(){
	// Initialize data managers
	ConfigManager.load();
	KC3Meta.init("../../../../data/");
	KC3QuestManager.load();
	KC3Database.init();
	KC3Translation.execute();

	// Apply interface configs
	$(".box-wrap").css("margin-top", ConfigManager.api_margin+"px");
	if(ConfigManager.api_bg_image === ""){
		$("body").css("background", ConfigManager.api_bg_color);
	}else{
		$("body").css("background-image", "url("+ConfigManager.api_bg_image+")");
		$("body").css("background-color", ConfigManager.api_bg_color);
		$("body").css("background-size", ConfigManager.api_bg_size);
		$("body").css("background-position", ConfigManager.api_bg_position);
		$("body").css("background-repeat", "no-repeat");
	}

	if(!(localStorage.absoluteswf || false)) {
		$(".box-nolink").show();
	}else{
		$(".box-wait .api_txt textarea").val(localStorage.absoluteswf);
		$(".box-wait").show();
	}

	$(".box-wait .api_txt").attr("title",KC3Meta.term("APIConcealExpl"));

	$(".box-wait .api_txt").on('change', 'textarea', function(){
		if(($(this).val().length > 0) || confirm("APIDataManualClear")) {
			localStorage.absoluteswf = $(this).val();
		} else {
			$(this).val(localStorage.absoluteswf);
		}
	});

	// Update API Link
	$(".api_submit").on('click', function(){
		if($(".api_text").val().indexOf("mainD2.swf") > -1){
			localStorage.absoluteswf = $(".api_text").val();
			window.location.reload();
		}
	});

	// Forget API Link
	$(".forget_btn").on('click', function(){
		localStorage.absoluteswf = "";
		window.location.reload();
	});

	// Quick Play
	$(".play_btn").on('click', function(){
		if($(this).data('play'))
			ActivateGame();
	});

	$(".play_btn").data('play',!ConfigManager.api_mustPanel);

	// Exit confirmation
	window.onbeforeunload = function(){
		ConfigManager.load();
		// added waiting condition should be ignored
		if(
			ConfigManager.api_askExit==1 &&
			!trustedExit &&
			!waiting &&
			$(".box-game").is(":visible") &&
			$(".game-refresh").text() > 0
		){
			trustedExit = true;
			setTimeout(function(){ trustedExit = false; }, 100);
			return KC3Meta.term("UnwantedExit");
		}
	};

	setInterval(function(){
		if(autoFocus===0){
			window.focus();
			$(".focus_regain").hide();
		}else{
			$(".focus_regain").show();
			$(".focus_val").css("width", (800*(autoFocus/20))+"px");
			autoFocus--;
		}
	}, 1000);
});

$(document).on("keydown", function(event){
	switch(event.keyCode) {
		// F7: Toggle keyboard focus
		case(118):
			autoFocus = 20;
			return false;

		// F9: Screenshot
		case(120):
			(new KCScreenshot()).start("Auto", $(".box-wrap"));
			return false;

		// F10: Clear overlays
		case(121):
			interactions.clearOverlays({}, {}, function(){});
			return false;

		// Other else
		default:
		break;
	}
});

/* Invokable actions
-----------------------------------*/
var interactions = {

	// Panel is opened, activate the game
	activateGame :function(request, sender, response){
		if(waiting){
			response({success:ActivateGame()});
		}else{
			response({success:false});
		}
	},

	// Cat Bomb Detection -> Enforced
	catBomb :function(request, sender, response){
		try{
			switch(Number(ConfigManager.api_directRefresh)) {
				case 0:
					throw new Error("");
				case 1:
					$(".game-refresh").text((0).toDigits(2)).css('right','0px');
					break;
				default:
					// TODO : Forced API Link Refresh
					$(".game-refresh").text((0).toDigits(2)).trigger('bomb-exploded');
					break;
			}
			return true;
		}catch(e){
			console.error(e);
		}finally{
			return false;
		}
	},

	// Quest page is opened, show overlays
	questOverlay :function(request, sender, response){
		//Only skip overlay generation if neither of the overlay features is enabled.
		if(!ConfigManager.api_translation && !ConfigManager.api_tracking){ response({success:false}); return true; }

		KC3QuestManager.load();
		$.each(request.questlist, function( index, QuestRaw ){
			// console.log("showing quest",QuestRaw);
			if( QuestRaw !=- 1 ){
				var QuestBox = $("#factory .ol_quest_exist").clone().appendTo(".overlay_quests");

				// Get quest data
				var QuestData = KC3QuestManager.get( QuestRaw.api_no );

				// Show meta, title and description
				if( typeof QuestData.meta().available != "undefined" ){

					if (ConfigManager.api_translation){
						$(".name", QuestBox).text( QuestData.meta().name );
						$(".desc", QuestBox).text( QuestData.meta().desc );
					}else{
						$(".content", QuestBox).css({opacity: 0});
					}

					if(ConfigManager.api_tracking){
						$(".tracking", QuestBox).html( QuestData.outputHtml() );
					}else{
						$(".tracking", QuestBox).hide();
					}

					// Special Bw1 case multiple requirements
					if( QuestRaw.api_no == 214 ){
						$(".tracking", QuestBox).addClass("small");
					}
				}else{
					QuestBox.css({ visibility: "hidden" });
				}
			}
		});
		response({success:true});
	},

	// Quest Progress Notification
	questProgress :function(request, sender, response){

		response({success:true});
	},

	// In-game record screen translation
	recordOverlay :function(request, sender, response){
		// app.Dom.applyRecordOverlay(request.record);
		response({success:true});
	},

	// Remove HTML overlays
	clearOverlays :function(request, sender, response){
		// console.log("clearing overlays");
		// app.Dom.clearOverlays();
		$(".overlay_quests").html("");
		$(".overlay_record").hide();
		response({success:true});
	},

	// Screenshot triggered, capture the visible tab
	screenshot :function(request, sender, response){
		// ~Please rewrite the screenshot script
		(new KCScreenshot()).start(request.playerName, $(".box-wrap"));
		response({success:true});
	},

	// Fit screen
	fitScreen :function(request, sender, response){
		var GameScale = ((ConfigManager.api_gameScale || 100) / 100);

		// Get browser zoon level for the page
		chrome.tabs.getZoom(null, function(ZoomFactor){
			// Resize the window
			chrome.windows.getCurrent(function(wind){
				chrome.windows.update(wind.id, {
					width: Math.ceil(800*GameScale*ZoomFactor) + (wind.width- Math.ceil($(window).width()*ZoomFactor) ),
					height: Math.ceil(480*GameScale*ZoomFactor) + (wind.height- Math.ceil($(window).height()*ZoomFactor) )
				});
			});
		});
	},

	// Taiha Alert Start
	taihaAlertStart :function(request, sender, response){
		$(".box-wrap").addClass("critical");

		if(critAnim){ clearInterval(critAnim); }
		critAnim = setInterval(function() {
			$(".taiha_red").toggleClass("anim2");
		}, 500);

		$(".taiha_blood").show();
		$(".taiha_red").show();
	},

	// Taiha Alert Stop
	taihaAlertStop :function(request, sender, response){
		$(".box-wrap").removeClass("critical");
		if(critAnim){ clearInterval(critAnim); }
		$(".taiha_blood").hide();
		$(".taiha_red").hide();
	}
};

/* Listen to messaging triggers
-----------------------------------*/
chrome.runtime.onMessage.addListener(function(request, sender, response){
	// If request is for this script
	if((request.identifier||"") == "kc3_gamescreen"){
		// If action requested is supported
		if(typeof interactions[request.action] !== "undefined"){
			// Execute the action
			interactions[request.action](request, sender, response);
			return true;
		}
	}
});
<commit_msg>Fix #1206 API Page Reload Confirmation<commit_after>_gaq.push(['_trackPageview']);

// If awaiting activation
var waiting = true;

// If trusted exit, for exit confirmation
var trustedExit = false;

// If auto-focus on window to capture key events or not
var autoFocus = 0;

// Critical Animation
var critAnim = false;

// Show game screens
function ActivateGame(){
	waiting = false;
	$(".box-wrap").css("background", "#fff");
	$(".box-wait").hide();
	$(".game-swf").remove();
	$(".box-game")
		.prepend("")
		.find(".game-swf")
		.attr("src", localStorage.absoluteswf)
		.end()
		.show();
	return true;
}

$(document).on("ready", function(){
	// Initialize data managers
	ConfigManager.load();
	KC3Meta.init("../../../../data/");
	KC3QuestManager.load();
	KC3Database.init();
	KC3Translation.execute();

	// Apply interface configs
	$(".box-wrap").css("margin-top", ConfigManager.api_margin+"px");
	if(ConfigManager.api_bg_image === ""){
		$("body").css("background", ConfigManager.api_bg_color);
	}else{
		$("body").css("background-image", "url("+ConfigManager.api_bg_image+")");
		$("body").css("background-color", ConfigManager.api_bg_color);
		$("body").css("background-size", ConfigManager.api_bg_size);
		$("body").css("background-position", ConfigManager.api_bg_position);
		$("body").css("background-repeat", "no-repeat");
	}

	if(!(localStorage.absoluteswf || false)) {
		$(".box-nolink").show();
	}else{
		$(".box-wait .api_txt textarea").val(localStorage.absoluteswf);
		$(".box-wait").show();
	}

	$(".box-wait .api_txt").attr("title",KC3Meta.term("APIConcealExpl"));

	$(".box-wait .api_txt").on('change', 'textarea', function(){
		if(($(this).val().length > 0) || confirm("APIDataManualClear")) {
			localStorage.absoluteswf = $(this).val();
		} else {
			$(this).val(localStorage.absoluteswf);
		}
	});

	// Update API Link
	$(".api_submit").on('click', function(){
		if($(".api_text").val().indexOf("mainD2.swf") > -1){
			localStorage.absoluteswf = $(".api_text").val();
			window.location.reload();
		}
	});

	// Forget API Link
	$(".forget_btn").on('click', function(){
		localStorage.absoluteswf = "";
		window.location.reload();
	});

	// Quick Play
	$(".play_btn").on('click', function(){
		if($(this).data('play'))
			ActivateGame();
	});

	$(".play_btn").data('play',!ConfigManager.api_mustPanel);

	// Exit confirmation
	window.onbeforeunload = function(){
		ConfigManager.load();
		// added waiting condition should be ignored
		if(
			ConfigManager.api_askExit==1 &&
			!trustedExit &&
			!waiting
		){
			trustedExit = true;
			setTimeout(function(){ trustedExit = false; }, 100);
			return KC3Meta.term("UnwantedExit");
		}
	};

	setInterval(function(){
		if(autoFocus===0){
			window.focus();
			$(".focus_regain").hide();
		}else{
			$(".focus_regain").show();
			$(".focus_val").css("width", (800*(autoFocus/20))+"px");
			autoFocus--;
		}
	}, 1000);
});

$(document).on("keydown", function(event){
	switch(event.keyCode) {
		// F7: Toggle keyboard focus
		case(118):
			autoFocus = 20;
			return false;

		// F9: Screenshot
		case(120):
			(new KCScreenshot()).start("Auto", $(".box-wrap"));
			return false;

		// F10: Clear overlays
		case(121):
			interactions.clearOverlays({}, {}, function(){});
			return false;

		// Other else
		default:
		break;
	}
});

/* Invokable actions
-----------------------------------*/
var interactions = {

	// Panel is opened, activate the game
	activateGame :function(request, sender, response){
		if(waiting){
			response({success:ActivateGame()});
		}else{
			response({success:false});
		}
	},

	// Cat Bomb Detection -> Enforced
	catBomb :function(request, sender, response){
		try{
			switch(Number(ConfigManager.api_directRefresh)) {
				case 0:
					throw new Error("");
				case 1:
					$(".game-refresh").text((0).toDigits(2)).css('right','0px');
					break;
				default:
					// TODO : Forced API Link Refresh
					$(".game-refresh").text((0).toDigits(2)).trigger('bomb-exploded');
					break;
			}
			return true;
		}catch(e){
			console.error(e);
		}finally{
			return false;
		}
	},

	// Quest page is opened, show overlays
	questOverlay :function(request, sender, response){
		//Only skip overlay generation if neither of the overlay features is enabled.
		if(!ConfigManager.api_translation && !ConfigManager.api_tracking){ response({success:false}); return true; }

		KC3QuestManager.load();
		$.each(request.questlist, function( index, QuestRaw ){
			// console.log("showing quest",QuestRaw);
			if( QuestRaw !=- 1 ){
				var QuestBox = $("#factory .ol_quest_exist").clone().appendTo(".overlay_quests");

				// Get quest data
				var QuestData = KC3QuestManager.get( QuestRaw.api_no );

				// Show meta, title and description
				if( typeof QuestData.meta().available != "undefined" ){

					if (ConfigManager.api_translation){
						$(".name", QuestBox).text( QuestData.meta().name );
						$(".desc", QuestBox).text( QuestData.meta().desc );
					}else{
						$(".content", QuestBox).css({opacity: 0});
					}

					if(ConfigManager.api_tracking){
						$(".tracking", QuestBox).html( QuestData.outputHtml() );
					}else{
						$(".tracking", QuestBox).hide();
					}

					// Special Bw1 case multiple requirements
					if( QuestRaw.api_no == 214 ){
						$(".tracking", QuestBox).addClass("small");
					}
				}else{
					QuestBox.css({ visibility: "hidden" });
				}
			}
		});
		response({success:true});
	},

	// Quest Progress Notification
	questProgress :function(request, sender, response){

		response({success:true});
	},

	// In-game record screen translation
	recordOverlay :function(request, sender, response){
		// app.Dom.applyRecordOverlay(request.record);
		response({success:true});
	},

	// Remove HTML overlays
	clearOverlays :function(request, sender, response){
		// console.log("clearing overlays");
		// app.Dom.clearOverlays();
		$(".overlay_quests").html("");
		$(".overlay_record").hide();
		response({success:true});
	},

	// Screenshot triggered, capture the visible tab
	screenshot :function(request, sender, response){
		// ~Please rewrite the screenshot script
		(new KCScreenshot()).start(request.playerName, $(".box-wrap"));
		response({success:true});
	},

	// Fit screen
	fitScreen :function(request, sender, response){
		var GameScale = ((ConfigManager.api_gameScale || 100) / 100);

		// Get browser zoon level for the page
		chrome.tabs.getZoom(null, function(ZoomFactor){
			// Resize the window
			chrome.windows.getCurrent(function(wind){
				chrome.windows.update(wind.id, {
					width: Math.ceil(800*GameScale*ZoomFactor) + (wind.width- Math.ceil($(window).width()*ZoomFactor) ),
					height: Math.ceil(480*GameScale*ZoomFactor) + (wind.height- Math.ceil($(window).height()*ZoomFactor) )
				});
			});
		});
	},

	// Taiha Alert Start
	taihaAlertStart :function(request, sender, response){
		$(".box-wrap").addClass("critical");

		if(critAnim){ clearInterval(critAnim); }
		critAnim = setInterval(function() {
			$(".taiha_red").toggleClass("anim2");
		}, 500);

		$(".taiha_blood").show();
		$(".taiha_red").show();
	},

	// Taiha Alert Stop
	taihaAlertStop :function(request, sender, response){
		$(".box-wrap").removeClass("critical");
		if(critAnim){ clearInterval(critAnim); }
		$(".taiha_blood").hide();
		$(".taiha_red").hide();
	}
};

/* Listen to messaging triggers
-----------------------------------*/
chrome.runtime.onMessage.addListener(function(request, sender, response){
	// If request is for this script
	if((request.identifier||"") == "kc3_gamescreen"){
		// If action requested is supported
		if(typeof interactions[request.action] !== "undefined"){
			// Execute the action
			interactions[request.action](request, sender, response);
			return true;
		}
	}
});
<|endoftext|>


<commit_before>import {Selection} from "./index.js";

export default function(selection) {
  if (!(selection instanceof Selection)) throw new Error("invalid merge");

  for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
    for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
      if (node = group0[i] || group1[i]) {
        merge[i] = node;
      }
    }
  }

  for (; j < m0; ++j) {
    merges[j] = groups0[j];
  }

  return new Selection(merges, this._parents);
}
<commit_msg>Implement selection.merge(transition) Closes #257<commit_after>import {Selection} from "./index.js";

export default function(context) {
  if (!(selection instanceof Selection) && !context.selection) throw new Error("invalid merge");
  var selection = context.selection ? context.selection() : context;

  for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
    for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
      if (node = group0[i] || group1[i]) {
        merge[i] = node;
      }
    }
  }

  for (; j < m0; ++j) {
    merges[j] = groups0[j];
  }

  return new Selection(merges, this._parents);
}
<|endoftext|>


<commit_before>import {
  hostname as getHostname,
  type as getOs,
  platform as getPlatform,
  release as getRelease,
  arch as getArch,
  totalmem as getMemory,
  cpus as getCpus,
  networkInterfaces as getNetworkInterfaces,
} from 'os'

// eslint-disable-next-line import/extensions
import uuidv5 from 'uuid/v5'

// Retrieve host-specific information
export const getHostInfo = function() {
  const id = getHostId()
  const name = getHostname()
  const os = getOs()
  const platform = getPlatform()
  const release = getRelease()
  const arch = getArch()
  const memory = getMemory()
  const cpus = getCpus().length

  return { id, name, os, platform, release, arch, memory, cpus }
}

// Unique id for a given host machine.
// We use UUIDv5 with the MAC address.
const getHostId = function() {
  const macAddress = getMacAddress()
  const hostId = uuidv5(macAddress, uuidv5.DNS)
  return hostId
}

const getMacAddress = function() {
  const ifaces = getNetworkInterfaces()
  const { mac: macA } =
    Object.values(ifaces)
      .flat()
      .find(({ internal, mac }) => !internal && mac) || {}

  if (macA === undefined) {
    return DEFAULT_MAC_ADDRESS
  }

  return macA
}

const DEFAULT_MAC_ADDRESS = '00:00:00:00:00:00'
<commit_msg>Fix linting<commit_after>import {
  hostname as getHostname,
  type as getOs,
  platform as getPlatform,
  release as getRelease,
  arch as getArch,
  totalmem as getMemory,
  cpus as getCpus,
  networkInterfaces as getNetworkInterfaces,
} from 'os'

import uuidv5 from 'uuid/v5.js'

// Retrieve host-specific information
export const getHostInfo = function() {
  const id = getHostId()
  const name = getHostname()
  const os = getOs()
  const platform = getPlatform()
  const release = getRelease()
  const arch = getArch()
  const memory = getMemory()
  const cpus = getCpus().length

  return { id, name, os, platform, release, arch, memory, cpus }
}

// Unique id for a given host machine.
// We use UUIDv5 with the MAC address.
const getHostId = function() {
  const macAddress = getMacAddress()
  const hostId = uuidv5(macAddress, uuidv5.DNS)
  return hostId
}

const getMacAddress = function() {
  const ifaces = getNetworkInterfaces()
  const { mac: macA } =
    Object.values(ifaces)
      .flat()
      .find(({ internal, mac }) => !internal && mac) || {}

  if (macA === undefined) {
    return DEFAULT_MAC_ADDRESS
  }

  return macA
}

const DEFAULT_MAC_ADDRESS = '00:00:00:00:00:00'
<|endoftext|>


<commit_before>
export default class Storage {

  /**
   * Set value to the storage
   *
   * @param {String} name
   * @param {Object/String/Number} value
   * @returns {Boolean}
   */
  static set(name, value) {
    if(window.localStorage) {
      return window.localStorage.setItem(name, JSON.stringify(value));
    }
  }

  /**
   * Get value from the storage
   *
   * @param {String} name
   * @returns {Object/String/Number} Retrurns FALSE
   */
  static get(name) {
    let value;

    if (window.localStorage) {
      value = window.localStorage.getItem(name);
      if (typeof value !== 'undefined') {
        try {
          return JSON.parse(value);
        }
        catch (e) {
          return value;
        }
      }
    }
    return false;
  }

  /**
   * Clear all stored data
   *
   * @returns {Boolean}
   */
  static clear() {
    if (window.localStorage) {
      return window.localStorage.clear();
    }

    return false;
  }
}
<commit_msg>Storage class refactored<commit_after>export default class Storage {
  /**
   * Set value to the storage
   *
   * @param {String} name
   * @param {Object/String/Number} value
   */
  static set(name, value) {
    window.localStorage && window.localStorage.setItem(name, JSON.stringify(value));
  }

  /**
   * Get value from the storage
   *
   * @param {String} name
   * @returns {Object/String/Number} value
   */
  static get(name) {
    const value = window.localStorage && window.localStorage.getItem(name);
    return value && JSON.parse(value);
  }

  /**
   * Clear all stored data
   *
   * @returns {Boolean}
   */
  static clear() {
    window.localStorage && window.localStorage.clear();
  }
}
<|endoftext|>