<commit_before>const RATING4U_MAX_WIDTH = 243;
const ERR_MSG_MAP = new Map();
ERR_MSG_MAP.set(1000, '出错啦！请把书名和链接反馈给作者，会尽快修正！');
ERR_MSG_MAP.set(1001, '没有找到您要的内容');

ERR_MSG_MAP.set(100, 'invalid_request_scheme 错误的请求协议');
ERR_MSG_MAP.set(101, 'invalid_request_method 错误的请求方法');
ERR_MSG_MAP.set(102, 'access_token_is_missing 未找到 access_token');
ERR_MSG_MAP.set(103, 'invalid_access_token access_token 不存在或已被用户删除，\
                          或者用户修改了密码');
ERR_MSG_MAP.set(104, 'invalid_apikey apikey 不存在或已删除');
ERR_MSG_MAP.set(105, 'apikey_is_blocked apikey 已被禁用');
ERR_MSG_MAP.set(106, 'access_token_has_expired access_token 已过期');
ERR_MSG_MAP.set(107, 'invalid_request_uri 请求地址未注册');
ERR_MSG_MAP.set(108, 'invalid_credencial1 用户未授权访问此数据');
ERR_MSG_MAP.set(109, 'invalid_credencial2 apikey 未申请此权限');
ERR_MSG_MAP.set(110, 'not_trial_user 未注册的测试用户');
ERR_MSG_MAP.set(111, 'rate_limit_exceeded1 用户访问速度限制');
ERR_MSG_MAP.set(112, 'IP 访问速度限制, 豆瓣限制您每小时最多只能发起100次请求');
ERR_MSG_MAP.set(113, 'required_parameter_is_missing 缺少参数');
ERR_MSG_MAP.set(114, 'unsupported_grant_type 错误的 grant_type');
ERR_MSG_MAP.set(115, 'unsupported_response_type 错误的 response_type');
ERR_MSG_MAP.set(116, 'client_secret_mismatch client_secret不匹配');
ERR_MSG_MAP.set(117, 'redirect_uri_mismatch redirect_uri不匹配');
ERR_MSG_MAP.set(118, 'invalid_authorization_code authorization_code 不存在或已过期');
ERR_MSG_MAP.set(119, 'invalid_refresh_token refresh_token 不存在或已过期');
ERR_MSG_MAP.set(120, 'username_password_mismatch 用户名密码不匹配');
ERR_MSG_MAP.set(121, 'invalid_user 用户不存在或已删除');
ERR_MSG_MAP.set(122, 'user_has_blocked 用户已被屏蔽');
ERR_MSG_MAP.set(123, 'access_token_has_expired_since_password_changed \
                          因用户修改密码而导致 access_token 过期');
ERR_MSG_MAP.set(124, 'access_token_has_not_expired access_token 未过期');
ERR_MSG_MAP.set(125, 'invalid_request_scope 访问的 scope 不合法，\
                          开发者不用太关注，一般不会出现该错误');
ERR_MSG_MAP.set(126, 'invalid_request_source 访问来源不合法');
ERR_MSG_MAP.set(127, 'thirdparty_login_auth_faied 第三方授权错误');
ERR_MSG_MAP.set(128, 'user_locked 用户被锁定');
ERR_MSG_MAP.set(999, 'unknown 未知错误');

class DoubanInfo extends BaseInfo {

    set options(options) {
        super.options = options;
        this.shortName = options.shortName;

        if (this.type === "book") {
            this.url = "https://api.douban.com/v2/book/search";
            this.author = options.author || ''; // 作者
        } else {
            this.url = "https://api.douban.com/v2/movie/search";
        }
        console.log('options: ', options);
    }

    /**
     * 生成查询用的参数对象
     *
     */
    getParams() {
        const params = {
            q : this.name
        };
        return params;
    }

    /**
     * 查询评分信息
     *
     */
    getRatingInfo(success, fail) {
        this.get(success, fail);
    }

    cutLongTagName(name) {
        const maxLength = RATING4U_MAX_WIDTH / 13 - 1;
        return name.substring(0, maxLength - 1) + '..';
    }

    sortTags(tags) {
         //将tag按长度从小到大排序，方便显示
        //tags.sort((a,b) => {
            //if (a.title.length > b.title.length) {
                //return 1;
            //} else if (a.title.length < b.title.length) {
                //return -1;
            //}
            //return 0;
        //});

        // 计算出当前tag的长度（px）
        const getTagLength = (tag) => {
            const num = tag.name.length;
            if (Util.matchCN(tag.name)) {
                return num * 13 + 22 + 6;
            }
            return num * 13 / 2 + 22 + 6;
        };

        const resultArr = [];
        while (tags.length > 0) {
            // 从数组最后端依次往前累加，得到最接近最大长度的组合
            let tempLength = 0;
            const indexArr = [];
            for (let i = tags.length-1; i >= 0; i--) {
                if (getTagLength(tags[i]) >= RATING4U_MAX_WIDTH) {
                    indexArr.push(i);
                    resultArr.push(this.cutLongTagName(tags[i].name));
                    break;
                }
                if (tempLength + getTagLength(tags[i]) < RATING4U_MAX_WIDTH) {
                    tempLength += getTagLength(tags[i]);
                    indexArr.push(i);
                    resultArr.push(tags[i].name);
                }
            }
            while (indexArr.length > 0) {
                tags.splice(indexArr.shift(), 1);
            }
        }
        return resultArr;
    }
    /**
     * 将当前作者按‘ ’或者‘，’‘,'分割，然后分别与jsonAuthor匹配，如果全部匹配则返回
     * true
     */
    isMatchAuthor(curAuthor, jsonAuthor) {
        const nameArr = curAuthor.replace(/[·|．|.|,|，]/, ' ').split(/\s/);
        for (const authorJ of jsonAuthor) {
            let isMatched = false;
            for (const namePart of nameArr) {
                if (authorJ.match(namePart)) {
                    isMatched = true;
                    break;
                }
            }
            if (isMatched) {
                return true;
            }
        }
        return false;
    }

    isMatchShortName(shortName, title) {
        for (const sname of shortName) {
            if (title.indexOf(sname) >= 0 ||
                    title.indexOf(sname.replace('，', ','))) {
                return true;
            }
        }
        return false;
    }

    /**
     * 从返回结果生成错误信息对象
     *
     */
    popError(json) {
        const data = {};
        data.type = this.type;

        const errJSON = json.responseJSON;
        if (errJSON) {
            data.errMsg = ERR_MSG_MAP.get(errJSON.code);
        } else {
            data.errMsg = ERR_MSG_MAP.get(1000);
        }

        return data;
    }

    /**
     * 从返回结果生成信息对象
     *
     */
    popData(json) {
        if (TEST_MODE) {
            return TEST_DATA_DOUBAN_MOVIE;
        }
        console.log('Request params: ', this.getParams());
        console.log('json result: ', json);
        const data = {};
        data.type = this.type;

        // total=0, 没有查询结果返回
        // total=-1，目前尚不知道是因为什么原因导致,通常再查询一遍就正常了
        if (json.total <= 0) {
            data.errMsg = ERR_MSG_MAP.get(1001);
        } else {
            if (this.type === "book") {
                for (const book of json.books) {
                    // 对于'东野圭吾：鸟人计划'，首先要重新匹配书名，因为结果
                    // 返回的可能是全部东野圭吾的作品
                    if ((this.isMatchShortName(this.shortName, book.title) ||
                            this.isMatchShortName(this.shortName, book.subtitle)) &&
                        // 根据作者匹配结果
                           (this.isMatchAuthor(this.author, book.author) ||
                        // 根据译者匹配结果
                            this.isMatchAuthor(this.author, book.translator) ||
                        // 有时作者是出版商
                            book.publisher.indexOf(this.author) !== -1 ||
                        // 如果没有作者信息则直接返回当前记录
                            this.author === '' || book.author.length === 0
                           )
                        ) {

                        data.id = book.id;
                        data.title = book.title;
                        data.originTitle = book.origin_title;
                        data.rating = book.rating.average;
                        data.ratingNum = book.rating.numRaters;
                        data.star = this.countStar(data.rating);
                        data.tags = this.sortTags(book.tags);

                        data.author = book.author.join('，');
                        data.translator = book.translator.join('，');
                        data.publisher = book.publisher;
                        data.summary = book.summary;

                        break;
                    }
                }

                // 如果没有结果返回
                if (!data.id) {
                    data.errMsg = ERR_MSG_MAP.get(1001);
                }

            } else {
                // 如果是电影信息
                // 根据年份得到精确的id，以便下一步取详细信息
                let id;
                if (this.year === '') {
                    id = json.subjects[0].id;
                } else {
                    for (const s of json.subjects) {
                        if (s.year == this.year) {
                            id = s.id;
                            break;
                        }
                    }
                }
                const movie = this.getSync(
                    'https://api.douban.com/v2/movie/subject/' + id);
                console.log('json movie:', movie);

                if (movie) {
                    data.id = movie.id;
                    data.title = movie.title;
                    data.originTitle = movie.original_title;
                    data.year = movie.year;
                    data.rating = movie.rating.average.toFixed(1);
                    data.ratingNum = movie.ratings_count || '';
                    data.genre = movie.genres;
                    data.star = movie.rating.stars;
                    data.summary = movie.summary;

                    // 得到影片的英文名，以方便之后在IMDB查询
                    if (data.originTitle && Util.isENStr(data.originTitle)) {
                        data.enName = data.originTitle;
                    } else {
                        const aka = movie.aka;
                        for (let i = aka.length-1;i >= 0;i--) {
                            if (!Util.isENStr(aka[i])) {
                                aka.splice(i, 1);
                            }
                        }

                        //将tag按长度从小到大排序，方便显示
                        aka.sort((a,b) => {
                            if (a.length < b.length) {
                                return 1;
                            } else if (a.length > b.length) {
                                return -1;
                            }
                            return 0;
                        });

                        if (aka.length > 0) {
                            data.enName = aka[0];
                        }
                    }

                    data.director = '';
                    data.stars = '';
                    for (const d of movie.directors) {
                        data.director += d.name + '，';
                    }
                    data.director = DoubanInfo.rmComma(data.director);
                    for (const c of movie.casts) {
                        data.stars += c.name + '，';
                    }
                    data.stars = DoubanInfo.rmComma(data.stars);
                } else {
                    // 如果没有结果返回
                    if (!data.id) {
                        data.errMsg = ERR_MSG_MAP.get(1001);
                    }
                }
            }
        }
        console.log('tip data', data);
        return data;
    }
}
<commit_msg>test submodule<commit_after>const RATING4U_MAX_WIDTH = 243;
const ERR_MSG_MAP = new Map();
ERR_MSG_MAP.set(1000, '出错啦！请把书名和链接反馈给作者，会尽快修正！');
ERR_MSG_MAP.set(1001, '没有找到您要的内容');

ERR_MSG_MAP.set(100, 'invalid_request_scheme 错误的请求协议');
ERR_MSG_MAP.set(101, 'invalid_request_method 错误的请求方法');
ERR_MSG_MAP.set(102, 'access_token_is_missing 未找到 access_token');
ERR_MSG_MAP.set(103, 'invalid_access_token access_token 不存在或已被用户删除，\
                          或者用户修改了密码');
ERR_MSG_MAP.set(104, 'invalid_apikey apikey 不存在或已删除');
ERR_MSG_MAP.set(105, 'apikey_is_blocked apikey 已被禁用');
ERR_MSG_MAP.set(106, 'access_token_has_expired access_token 已过期');
ERR_MSG_MAP.set(107, 'invalid_request_uri 请求地址未注册');
ERR_MSG_MAP.set(108, 'invalid_credencial1 用户未授权访问此数据');
ERR_MSG_MAP.set(109, 'invalid_credencial2 apikey 未申请此权限');
ERR_MSG_MAP.set(110, 'not_trial_user 未注册的测试用户');
ERR_MSG_MAP.set(111, 'rate_limit_exceeded1 用户访问速度限制');
ERR_MSG_MAP.set(112, 'IP 访问速度限制, 豆瓣限制您每小时最多只能发起100次请求');
ERR_MSG_MAP.set(113, 'required_parameter_is_missing 缺少参数');
ERR_MSG_MAP.set(114, 'unsupported_grant_type 错误的 grant_type');
ERR_MSG_MAP.set(115, 'unsupported_response_type 错误的 response_type');
ERR_MSG_MAP.set(116, 'client_secret_mismatch client_secret不匹配');
ERR_MSG_MAP.set(117, 'redirect_uri_mismatch redirect_uri不匹配');
ERR_MSG_MAP.set(118, 'invalid_authorization_code authorization_code 不存在或已过期');
ERR_MSG_MAP.set(119, 'invalid_refresh_token refresh_token 不存在或已过期');
ERR_MSG_MAP.set(120, 'username_password_mismatch 用户名密码不匹配');
ERR_MSG_MAP.set(121, 'invalid_user 用户不存在或已删除');
ERR_MSG_MAP.set(122, 'user_has_blocked 用户已被屏蔽');
ERR_MSG_MAP.set(123, 'access_token_has_expired_since_password_changed \
                          因用户修改密码而导致 access_token 过期');
ERR_MSG_MAP.set(124, 'access_token_has_not_expired access_token 未过期');
ERR_MSG_MAP.set(125, 'invalid_request_scope 访问的 scope 不合法，\
                          开发者不用太关注，一般不会出现该错误');
ERR_MSG_MAP.set(126, 'invalid_request_source 访问来源不合法');
ERR_MSG_MAP.set(127, 'thirdparty_login_auth_faied 第三方授权错误');
ERR_MSG_MAP.set(128, 'user_locked 用户被锁定');
ERR_MSG_MAP.set(999, 'unknown 未知错误');

class DoubanInfo extends BaseInfo {

    set options(options) {
        super.options = options;
        this.shortName = options.shortName;

        if (this.type === "book") {
            this.url = "https://api.douban.com/v2/book/search";
            this.author = options.author || ''; // 作者
        } else {
            this.url = "https://api.douban.com/v2/movie/search";
        }
        console.log('options: ', options);
    }

    /**
     * 生成查询用的参数对象
     *
     */
    getParams() {
        const params = {
            q : this.name
        };
        return params;
    }

    /**
     * 查询评分信息
     *
     */
    getRatingInfo(success, fail) {
        this.get(success, fail);
    }

    cutLongTagName(name) {
        const maxLength = RATING4U_MAX_WIDTH / 13 - 1;
        return name.substring(0, maxLength - 1) + '..';
    }

    sortTags(tags) {
         //将tag按长度从小到大排序，方便显示
        //tags.sort((a,b) => {
            //if (a.title.length > b.title.length) {
                //return 1;
            //} else if (a.title.length < b.title.length) {
                //return -1;
            //}
            //return 0;
        //});

        // 计算出当前tag的长度（px）
        const getTagLength = (tag) => {
            const num = tag.name.length;
            if (Util.matchCN(tag.name)) {
                return num * 13 + 22 + 6;
            }
            return num * 13 / 2 + 22 + 6;
        };

        const resultArr = [];
        while (tags.length > 0) {
            // 从数组最后端依次往前累加，得到最接近最大长度的组合
            let tempLength = 0;
            const indexArr = [];
            for (let i = tags.length-1; i >= 0; i--) {
                if (getTagLength(tags[i]) >= RATING4U_MAX_WIDTH) {
                    indexArr.push(i);
                    resultArr.push(this.cutLongTagName(tags[i].name));
                    break;
                }
                if (tempLength + getTagLength(tags[i]) < RATING4U_MAX_WIDTH) {
                    tempLength += getTagLength(tags[i]);
                    indexArr.push(i);
                    resultArr.push(tags[i].name);
                }
            }
            while (indexArr.length > 0) {
                tags.splice(indexArr.shift(), 1);
            }
        }
        return resultArr;
    }
    /**
     * 将当前作者按‘ ’或者‘，’‘,'分割，然后分别与jsonAuthor匹配，如果全部匹配则返回
     * true
     */
    isMatchAuthor(curAuthor, jsonAuthor) {
        const nameArr = curAuthor.replace(/[·|．|.|,|，]/, ' ').split(/\s/);
        for (const authorJ of jsonAuthor) {
            let isMatched = false;
            for (const namePart of nameArr) {
                if (authorJ.match(namePart)) {
                    isMatched = true;
                    break;
                }
            }
            if (isMatched) {
                return true;
            }
        }
        return false;
    }

    isMatchShortName(shortName, title) {
        for (const sname of shortName) {
            if (title.indexOf(sname) >= 0 ||
                    title.indexOf(sname.replace('，', ','))) {
                return true;
            }
        }
        return false;
    }

    /**
     * 从返回结果生成错误信息对象
     *
     */
    popError(json) {
        const data = {};
        data.type = this.type;

        const errJSON = json.responseJSON;
        if (errJSON) {
            data.errMsg = ERR_MSG_MAP.get(errJSON.code);
        } else {
            data.errMsg = ERR_MSG_MAP.get(1000);
        }

        return data;
    }

    /**
     * 从返回结果生成信息对象
     *
     */
    popData(json) {
        if (TEST_MODE) {
            return TEST_DATA_DOUBAN_MOVIE;
        }
        console.log('Request params: ', this.getParams());
        console.log('json result: ', json);
        const data = {};
        data.type = this.type;

        // total=0, 没有查询结果返回
        // total=-1，目前尚不知道是因为什么原因导致,通常再查询一遍就正常了
        if (json.total <= 0) {
            data.errMsg = ERR_MSG_MAP.get(1001);
        } else {
            if (this.type === "book") {
                for (const book of json.books) {
                    // 对于'东野圭吾：鸟人计划'，首先要重新匹配书名，因为结果
                    // 返回的可能是全部东野圭吾的作品
                    if ((this.isMatchShortName(this.shortName, book.title) ||
                            this.isMatchShortName(this.shortName, book.subtitle)) &&
                        // 根据作者匹配结果
                           (this.isMatchAuthor(this.author, book.author) ||
                        // 根据译者匹配结果
                            this.isMatchAuthor(this.author, book.translator) ||
                        // 有时作者是出版商
                            book.publisher.indexOf(this.author) !== -1 ||
                        // 如果没有作者信息则直接返回当前记录
                            this.author === '' || book.author.length === 0
                           )
                        ) {

                        data.id = book.id;
                        data.title = book.title;
                        data.originTitle = book.origin_title;
                        data.rating = book.rating.average;
                        data.ratingNum = book.rating.numRaters;
                        data.star = this.countStar(data.rating);
                        data.tags = this.sortTags(book.tags);

                        data.author = book.author.join('，');
                        data.translator = book.translator.join('，');
                        data.publisher = book.publisher;
                        data.summary = book.summary;

                        break;
                    }
                }

                // 如果没有结果返回
                if (!data.id) {
                    data.errMsg = ERR_MSG_MAP.get(1001);
                }

            } else {
                // 如果是电影信息
                // 根据年份得到精确的id，以便下一步取详细信息
                let id;
                if (this.year === '') {
                    id = json.subjects[0].id;
                } else {
                    for (const s of json.subjects) {
                        if (s.year == this.year) {
                            id = s.id;
                            break;
                        }
                    }
                }

                const movie = this.getSync(
                    'https://api.douban.com/v2/movie/subject/' + id);
                console.log('json movie:', movie);

                if (movie) {
                    data.id = movie.id;
                    data.title = movie.title;
                    data.originTitle = movie.original_title;
                    data.year = movie.year;
                    data.rating = movie.rating.average.toFixed(1);
                    data.ratingNum = movie.ratings_count || '';
                    data.genre = movie.genres;
                    data.star = movie.rating.stars;
                    data.summary = movie.summary;

                    // 得到影片的英文名，以方便之后在IMDB查询
                    if (data.originTitle && Util.isENStr(data.originTitle)) {
                        data.enName = data.originTitle;
                    } else {
                        const aka = movie.aka;
                        for (let i = aka.length-1;i >= 0;i--) {
                            if (!Util.isENStr(aka[i])) {
                                aka.splice(i, 1);
                            }
                        }

                        //将tag按长度从小到大排序，方便显示
                        aka.sort((a,b) => {
                            if (a.length < b.length) {
                                return 1;
                            } else if (a.length > b.length) {
                                return -1;
                            }
                            return 0;
                        });

                        if (aka.length > 0) {
                            data.enName = aka[0];
                        }
                    }

                    data.director = '';
                    data.stars = '';
                    for (const d of movie.directors) {
                        data.director += d.name + '，';
                    }
                    data.director = DoubanInfo.rmComma(data.director);
                    for (const c of movie.casts) {
                        data.stars += c.name + '，';
                    }
                    data.stars = DoubanInfo.rmComma(data.stars);
                } else {
                    // 如果没有结果返回
                    if (!data.id) {
                        data.errMsg = ERR_MSG_MAP.get(1001);
                    }
                }
            }
        }
        console.log('tip data', data);
        return data;
    }
}
<|endoftext|>


<commit_before>'use strict';

var scene = [];
var sceneLoader = [];
var onSceneOpen = [];
var onSceneClose = [];

var lastScene = null;
var currentScene = null;
var animDelay = 33;
var sceneAnimationTime = 350;

// No animation at all
function setScene(newScene) {
  lastScene = currentScene;
  currentScene = newScene;
  scene[currentScene].playSceneMusic();
  UpdateScreen();
}

// With animation
function changeScene(newScene) {
  var elapsedTime = 0;

  // Changing to new scene
  lastScene = currentScene;
  currentScene = newScene;

  // Interval when both scenes appear at the same time
  scene[lastScene].disableSceneInteractiveness();
  scene[currentScene].disableSceneInteractiveness();
  scene[currentScene].saveAlphaValues();
  scene[currentScene].setFade(0);

  // Play new music
  scene[currentScene].playSceneMusic();

  // Running method for scene opened
  if (onSceneOpen[currentScene] != null) {
    onSceneOpen[currentScene]();
  }
  // Running method for scene closed
  if (onSceneClose[lastScene] != null) {
    onSceneClose[lastScene]();
  }

  var sceneFadeInterval = setInterval( function() {
    elapsedTime += animDelay;
    // Not finished animation
    if (elapsedTime < sceneAnimationTime) {
      // Draw the older scene
      scene[lastScene].showScene();
      // Change the newer scene fade
      scene[currentScene].setFade(elapsedTime/sceneAnimationTime);
    }
    // Finished animation
    else {
      scene[lastScene].enableSceneInteractiveness();
      scene[currentScene].enableSceneInteractiveness();
      scene[currentScene].setFade(1);
      clearInterval(sceneFadeInterval); // Stop calling itself
    }
    UpdateScreen();
  }, animDelay);
}

function UpdateScreen() {
  scene[currentScene].showScene();
  ScreenUpdateRequest();
}
<commit_msg>update scene screen immediatally after changing scenes (1 frame was missing)<commit_after>'use strict';

var scene = [];
var sceneLoader = [];
var onSceneOpen = [];
var onSceneClose = [];

var lastScene = null;
var currentScene = null;
var animDelay = 33;
var sceneAnimationTime = 350;
var elapsedTime = 0;
var sceneFadeInterval;

// No animation at all
function setScene(newScene) {
  lastScene = currentScene;
  currentScene = newScene;
  scene[currentScene].playSceneMusic();
  UpdateScreen();
}

// With animation
function changeScene(newScene) {
  elapsedTime = 0;

  // Changing to new scene
  lastScene = currentScene;
  currentScene = newScene;

  // Interval when both scenes appear at the same time
  scene[lastScene].disableSceneInteractiveness();
  scene[currentScene].disableSceneInteractiveness();
  scene[currentScene].saveAlphaValues();
  scene[currentScene].setFade(0);

  // Play new music
  scene[currentScene].playSceneMusic();

  // Running method for scene opened
  if (onSceneOpen[currentScene] != null) {
    onSceneOpen[currentScene]();
  }
  // Running method for scene closed
  if (onSceneClose[lastScene] != null) {
    onSceneClose[lastScene]();
  }

  sceneFade();
  sceneFadeInterval = setInterval(sceneFade, animDelay);
}

function sceneFade() {
  elapsedTime += animDelay;
  // Not finished animation
  if (elapsedTime < sceneAnimationTime) {
    // Draw the older scene
    scene[lastScene].showScene();
    // Change the newer scene fade
    scene[currentScene].setFade(elapsedTime/sceneAnimationTime);
  }
  // Finished animation
  else {
    scene[lastScene].enableSceneInteractiveness();
    scene[currentScene].enableSceneInteractiveness();
    scene[currentScene].setFade(1);
    clearInterval(sceneFadeInterval); // Stop calling itself
  }
  UpdateScreen();
}

function UpdateScreen() {
  scene[currentScene].showScene();
  ScreenUpdateRequest();
}
<|endoftext|>


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

/**
 * External dependencies
 */
import invariant from 'invariant';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import Data from 'googlesitekit-data';
import { STORE_NAME } from './constants';
import { createFetchStore } from '../../data/create-fetch-store';
import { createValidatedAction } from '../../data/utils';

const { createRegistrySelector, commonActions } = Data;
const { getRegistry } = commonActions;

function reducerCallback( state, dismissedItems ) {
	return {
		...state,
		dismissedItems: Array.isArray( dismissedItems ) ? dismissedItems : [],
	};
}

const fetchGetDismissedItemsStore = createFetchStore( {
	baseName: 'getDismissedItems',
	controlCallback: () => API.get( 'core', 'user', 'dismissed-items', {}, { useCache: false } ),
	reducerCallback,
} );

const fetchDismissItemStore = createFetchStore( {
	baseName: 'dismissItem',
	controlCallback: ( { slug, expiresInSeconds } ) => API.set( 'core', 'user', 'dismiss-item', { slug, expiresInSeconds } ),
	reducerCallback,
	argsToParams: ( { slug, expiresInSeconds = 0 } ) => {
		return ( { slug, expiresInSeconds } );
	},
	validateParams: ( { slug, expiresInSeconds } = {} ) => {
		invariant( slug, 'slug is required.' );
		invariant( Number.isInteger( expiresInSeconds ), 'expiresInSeconds should be an integer.' );
	},
} );

const baseInitialState = {
	dismissedItems: undefined,
};

const baseActions = {
	/**
	 * Dismisses the given item by slug.
	 *
	 * @since n.e.x.t
	 *
	 * @param {string} slug Item slug to dismiss.
	 * @return {Object} Generator instance.
	 */
	dismissItem: createValidatedAction(
		( slug ) => {
			invariant( slug, 'A tour slug is required to dismiss a tour.' );
		},
		function* ( slug ) {
			return yield fetchDismissItemStore.actions.fetchDismissItem( slug );
		},
	),
};

const baseResolvers = {
	*getDismissedItems() {
		const { select } = yield getRegistry();
		const dismissedItems = select( STORE_NAME ).getDismissedItems();
		if ( dismissedItems === undefined ) {
			yield fetchGetDismissedItemsStore.actions.fetchGetDismissedItems();
		}
	},
};

const baseSelectors = {
	/**
	 * Gets the list of dismissed items.
	 *
	 * @since n.e.x.t
	 *
	 * @param {Object} state Data store's state.
	 * @return {(string[]|undefined)} Array of dismissed item slugs, `undefined` if not resolved yet.
	 */
	getDismissedItems( state ) {
		return state.dismissedItems;
	},

	/**
	 * Determines whether the item is dismissed or not.
	 *
	 * @since n.e.x.t
	 *
	 * @param {Object} state Data store's state.
	 * @param {string} slug  Item slug.
	 * @return {(boolean|undefined)} TRUE if dismissed, otherwise FALSE, `undefined` if not resolved yet.
	 */
	isItemDismissed: createRegistrySelector( ( select ) => ( state, slug ) => {
		return select( STORE_NAME ).getDismissedItems()?.includes( slug );
	} ),
};

export const {
	actions,
	controls,
	initialState,
	reducer,
	resolvers,
	selectors,
} = Data.combineStores(
	{
		initialState: baseInitialState,
		actions: baseActions,
		resolvers: baseResolvers,
		selectors: baseSelectors,
	},
	fetchDismissItemStore,
	fetchGetDismissedItemsStore,
);

export default {
	actions,
	controls,
	initialState,
	reducer,
	resolvers,
	selectors,
};
<commit_msg>Update signature of dismissItem action.<commit_after>/**
 * `core/user` data store: dismissed items
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import invariant from 'invariant';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import Data from 'googlesitekit-data';
import { STORE_NAME } from './constants';
import { createFetchStore } from '../../data/create-fetch-store';
import { createValidatedAction } from '../../data/utils';

const { createRegistrySelector, commonActions } = Data;
const { getRegistry } = commonActions;

function reducerCallback( state, dismissedItems ) {
	return {
		...state,
		dismissedItems: Array.isArray( dismissedItems ) ? dismissedItems : [],
	};
}

const fetchGetDismissedItemsStore = createFetchStore( {
	baseName: 'getDismissedItems',
	controlCallback: () => API.get( 'core', 'user', 'dismissed-items', {}, { useCache: false } ),
	reducerCallback,
} );

const fetchDismissItemStore = createFetchStore( {
	baseName: 'dismissItem',
	controlCallback: ( { slug, expiresInSeconds } ) => API.set( 'core', 'user', 'dismiss-item', { slug, expiresInSeconds } ),
	reducerCallback,
	argsToParams: ( { slug, expiresInSeconds = 0 } ) => {
		return ( { slug, expiresInSeconds } );
	},
	validateParams: ( { slug, expiresInSeconds } = {} ) => {
		invariant( slug, 'slug is required.' );
		invariant( Number.isInteger( expiresInSeconds ), 'expiresInSeconds should be an integer.' );
	},
} );

const baseInitialState = {
	dismissedItems: undefined,
};

const baseActions = {
	/**
	 * Dismisses the given item by slug.
	 *
	 * @since n.e.x.t
	 *
	 * @param {string} slug             Item slug to dismiss.
	 * @param {number} expiresInSeconds An integer number of seconds for expiry. 0 denotes permanent dismissal.
	 * @return {Object} Generator instance.
	 */
	dismissItem: createValidatedAction(
		( slug, expiresInSeconds = 0 ) => {
			invariant( slug, 'A tour slug is required to dismiss a tour.' );
			invariant( Number.isInteger( expiresInSeconds ), 'expiresInSeconds should be an integer.' );
		},
		function* ( slug, expiresInSeconds ) {
			return yield fetchDismissItemStore.actions.fetchDismissItem( slug, expiresInSeconds );
		},
	),
};

const baseResolvers = {
	*getDismissedItems() {
		const { select } = yield getRegistry();
		const dismissedItems = select( STORE_NAME ).getDismissedItems();
		if ( dismissedItems === undefined ) {
			yield fetchGetDismissedItemsStore.actions.fetchGetDismissedItems();
		}
	},
};

const baseSelectors = {
	/**
	 * Gets the list of dismissed items.
	 *
	 * @since n.e.x.t
	 *
	 * @param {Object} state Data store's state.
	 * @return {(string[]|undefined)} Array of dismissed item slugs, `undefined` if not resolved yet.
	 */
	getDismissedItems( state ) {
		return state.dismissedItems;
	},

	/**
	 * Determines whether the item is dismissed or not.
	 *
	 * @since n.e.x.t
	 *
	 * @param {Object} state Data store's state.
	 * @param {string} slug  Item slug.
	 * @return {(boolean|undefined)} TRUE if dismissed, otherwise FALSE, `undefined` if not resolved yet.
	 */
	isItemDismissed: createRegistrySelector( ( select ) => ( state, slug ) => {
		return select( STORE_NAME ).getDismissedItems()?.includes( slug );
	} ),
};

export const {
	actions,
	controls,
	initialState,
	reducer,
	resolvers,
	selectors,
} = Data.combineStores(
	{
		initialState: baseInitialState,
		actions: baseActions,
		resolvers: baseResolvers,
		selectors: baseSelectors,
	},
	fetchDismissItemStore,
	fetchGetDismissedItemsStore,
);

export default {
	actions,
	controls,
	initialState,
	reducer,
	resolvers,
	selectors,
};
<|endoftext|>


<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return /* Your Expression */;
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return /* Your Expression */;
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    /* YOUR CODE HERE */
    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<commit_msg>3.6 Unit 3 Homework assignment<commit_after>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move || getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move || randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    /* YOUR CODE HERE */
    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<|endoftext|>


<commit_before>/**
	@author Martin Vézina, 2012-06
	Loads content through AJAX and create it as an AsyncContentTransition. The definition of a transition must be included in a script with class "async", that sets

	This script will be injected in the dom and called immediately so as to extend the object with the defined transition.

*/
(function (root, factory) {
	var nsParts = 'lagrange/content/ContentFactory'.split('/');
	var name = nsParts.pop();
	var ns = nsParts.reduce(function(prev, part){
		return prev[part] = (prev[part] || {});
	}, root);
	if (typeof define === 'function' && define.amd) {
		define(
			'lagrange/content/ContentFactory',//must be a string, not a var
			[
				'jquery',
				'lagrange/content/Async'
			], function ($, Async) {
			return (ns[name] = factory($, Async));
		});
	} else {
		ns[name] = factory(root.$, root.lagrange.content.Async);
	}
}(this, function ($, Async) {

	var cachedDeferred = {};
	var putDeferredToCache = function(id, deferred) {
		//cachedDeferred[id] = deferred;
	};

	var createLoadedContent = function(rawResponse, createParams, createContentCallback) {

		var title = rawResponse.filter('title').html();
		var asyncExtender = Async.getExtender(rawResponse);
		var noscriptResponse = asyncExtender.getFilteredResponse();

		createParams.title = title;
		var content = createContentCallback(noscriptResponse, createParams, noscriptResponse);
		content = asyncExtender.extend(content);

		return content;
	};

	var getFromAjax = function(path, createParams, selector, createContentCallback) {

		var ajax = $.ajax({
			url : path,
			dataType :'html'
		});
		var success = function(data, textStatus, jqXHR) {
			return createLoadedContent($(data), createParams, selector, createContentCallback);
		};

		var fail = function(jqXHR, textStatus, errorThrown) {
			putDeferredToCache(createParams.id, null);
			console.log(textStatus, jqXHR.responseText);
		};

		var filtered = ajax.pipe(success, fail);

		putDeferredToCache(createParams.id, filtered.promise());
		return filtered.promise();
	};

	var getFromCache = function(id) {
		if(cachedDeferred[id]) {
			//console.log(path+' from cache');
			return cachedDeferred[id];
		}
		return false;
	};

	var getParams = function(path, title) {
		return {
			id : Async.getPagePart(path),
			path : path,
			title : title
		};
	};

	return {

		getNodeFromSelector : function(input, selector){
			var node = selector ? $(selector, input) : $('<div>').append(input);
			//si le node n'est pas trouvé avec le selector, il est possible que le node soit au premier niveau du jquery donné
			if(node.length == 0 && selector){
				node = input.filter(selector);
			}
			return node;
		},

		//si la page est celle affichée au load (donc pas par ajax) il faut quand meme la créer parce qu'elle doit exister pour la navigation. i.e. elle doit avoir le meme comportement qu'une page qui serait loadée par ajax
		createOriginalContent : function(path, title) {
			var createParams = getParams(path, title);
			var content = this.createContent(null, createParams);

			var asyncExtender = Async.getExtender();
			content = asyncExtender.extend(content);

			var deferred = $.Deferred();
			deferred.resolve(content);
			putDeferredToCache(createParams.id, deferred.promise());
			return content;
		},

		getPageId : function(path){
			var createParams = getParams(path);
			return createParams.id;
		},

		/**
		ABSTRACT Crée l'objet de page. La fonction doit être overridée par les sous-classes pour crer d'autres types de contenus.
		*/
		createContent : function() {
			throw new Error('createContent is abstract');
		},

		/**
		ABSTRACT
		*/
		load : function() {
			throw new Error('load is abstract');
		},

		getLoadingDeferred : function(path){

			createParams = getParams(path);

			return getFromCache(createParams.id) || getFromAjax(path, createParams, this.createContent.bind(this));

		}
	};

}));<commit_msg>removed cache in async content<commit_after>/**
	@author Martin Vézina, 2012-06
	Loads content through AJAX and create it as an AsyncContentTransition. The definition of a transition must be included in a script with class "async", that sets

	This script will be injected in the dom and called immediately so as to extend the object with the defined transition.

*/
(function (root, factory) {
	var nsParts = 'lagrange/content/ContentFactory'.split('/');
	var name = nsParts.pop();
	var ns = nsParts.reduce(function(prev, part){
		return prev[part] = (prev[part] || {});
	}, root);
	if (typeof define === 'function' && define.amd) {
		define(
			'lagrange/content/ContentFactory',//must be a string, not a var
			[
				'jquery',
				'lagrange/content/Async'
			], function ($, Async) {
			return (ns[name] = factory($, Async));
		});
	} else {
		ns[name] = factory(root.$, root.lagrange.content.Async);
	}
}(this, function ($, Async) {

	var createLoadedContent = function(rawResponse, createParams, createContentCallback) {

		var title = rawResponse.filter('title').html();
		var asyncExtender = Async.getExtender(rawResponse);
		var noscriptResponse = asyncExtender.getFilteredResponse();

		createParams.title = title;
		var content = createContentCallback(noscriptResponse, createParams, noscriptResponse);
		content = asyncExtender.extend(content);

		return content;
	};

	var getFromAjax = function(path, createParams, selector, createContentCallback) {

		var ajax = $.ajax({
			url : path,
			dataType :'html'
		});
		var success = function(data, textStatus, jqXHR) {
			return createLoadedContent($(data), createParams, selector, createContentCallback);
		};

		var fail = function(jqXHR, textStatus, errorThrown) {
			console.log(textStatus, jqXHR.responseText);
		};

		var filtered = ajax.pipe(success, fail);

		return filtered.promise();
	};

	var getParams = function(path, title) {
		return {
			id : Async.getPagePart(path),
			path : path,
			title : title
		};
	};

	return {

		getNodeFromSelector : function(input, selector){
			var node = selector ? $(selector, input) : $('<div>').append(input);
			//si le node n'est pas trouvé avec le selector, il est possible que le node soit au premier niveau du jquery donné
			if(node.length == 0 && selector){
				node = input.filter(selector);
			}
			return node;
		},

		//si la page est celle affichée au load (donc pas par ajax) il faut quand meme la créer parce qu'elle doit exister pour la navigation. i.e. elle doit avoir le meme comportement qu'une page qui serait loadée par ajax
		createOriginalContent : function(path, title) {
			var createParams = getParams(path, title);
			var content = this.createContent(null, createParams);

			var asyncExtender = Async.getExtender();
			content = asyncExtender.extend(content);

			var deferred = $.Deferred();
			deferred.resolve(content);
			return content;
		},

		getPageId : function(path){
			var createParams = getParams(path);
			return createParams.id;
		},

		/**
		ABSTRACT Crée l'objet de page. La fonction doit être overridée par les sous-classes pour crer d'autres types de contenus.
		*/
		createContent : function() {
			throw new Error('createContent is abstract');
		},

		/**
		ABSTRACT
		*/
		load : function() {
			throw new Error('load is abstract');
		},

		getLoadingDeferred : function(path){

			createParams = getParams(path);

			return getFromAjax(path, createParams, this.createContent.bind(this));

		}
	};

}));<|endoftext|>


<commit_before>"use strict";
// This file holds the constructor functions for
// gameplay/animation/etc. objects

sf.objects.GameObject = {
    moveBy: function(x, y) {
        this.calculateBounds();
        if (this.movable) {
            this.prevpos.x = this.pos.x;
            this.prevpos.y = this.pos.y;
            this.pos.x = this.pos.x + x;
            this.pos.y = this.pos.y + y;
            this.calculateBounds();
        }
    },
    moveBack: function() {
        this.pos.x = this.prevpos.x;
        this.pos.y = this.prevpos.y;
        this.calculateBounds();
    },
    calculateBounds: function() {

        this.bounds.top = this.pos.y - (this.outerheight/2);
        this.bounds.left = this.pos.x - (this.outerwidth/2);
        this.bounds.bottom = this.pos.y + (this.outerheight/2);
        this.bounds.right = this.pos.x + (this.outerwidth/2);

        this.prevbounds.top = this.prevpos.y - (this.outerheight/2);
        this.prevbounds.left = this.prevpos.x - (this.outerwidth/2);
        this.prevbounds.bottom = this.prevpos.y + (this.outerheight/2);
        this.prevbounds.right = this.prevpos.x + (this.outerwidth/2);

        // For some aggressive optimization of collision detection...
        this.movebounds.top = (this.bounds.top < this.prevbounds.top) ? this.bounds.top : this.prevbounds.top;
        this.movebounds.left = (this.bounds.left < this.prevbounds.left) ? this.bounds.left : this.prevbounds.left;
        this.movebounds.bottom = (this.bounds.bottom > this.prevbounds.bottom) ? this.bounds.bottom : this.prevbounds.bottom;
        this.movebounds.right = (this.bounds.right > this.prevbounds.right) ? this.bounds.right : this.prevbounds.right;
        if (this.movebounds.right <= this.movebounds.left || this.movebounds.bottom <= this.movebounds.top) {
            console.log('STUFF SERIOUSLY WRONG, movebounds:', this.movebounds)
        }

    },
    areaCollision: function(that) { // This collision detection is for first pruning of cases.
        if (this.movebounds.right > that.movebounds.left &&
            that.movebounds.right > this.movebounds.left &&
            this.movebounds.bottom > that.movebounds.top &&
            that.movebounds.bottom > this.movebounds.top) {
            return true;
        }
        else {
            // console.log(this, that);
            return false;
        }
    },
    crudeCollision: function(that) { // This collision detection is for simple cases. Only run after getting true from areaCollision!
        return true; // doesn't do anything really yet...
    },
    hitboxCollision: function(that) { // this collision function is for most definite cases. Only run after getting true from crudeCollision!
        return true; // doesn't do anything really yet...
    },
    collision: function(that) { // Remember to run calculateBounds for both this and that before asking collision!
        //console.log('Calling collision!');
        return (this.areaCollision(that) && this.crudeCollision(that) && this.hitboxCollision(that));
    },
    init: function(posX, posY, movable, outerwidth, outerheight, blocking) {
        this.pos = {x: posX, y: posY };
        this.prevpos = {x: posX, y: posY };
        this.movable = movable;
        this.outerwidth = outerwidth;
        this.outerheight= outerheight;
        this.bounds = {};
        this.prevbounds = {};
        this.movebounds = {};
        this.calculateBounds();
        this.active = false;
        if (typeof blocking === 'undefined') {this.blocking = false;}
        else {this.blocking = blocking;}
        this.color = 'rgb(0,0,0)';
    },
    draw: function(context, drawColor) {
        if (typeof drawColor === 'undefined') {var drawColor=this.color;}
        if (!this.sprite) {
            context.fillStyle=drawColor;
            context.fillRect(this.bounds.left, this.bounds.top, this.outerwidth, this.outerheight);
        }
    },
    tick: function() { // overwrite this function for objects that that actually do something.
    },
    shoutInfo: function() {
        console.log(this);
    }
};

<commit_msg>arrayCollision function to gameobject<commit_after>"use strict";
// This file holds the constructor functions for
// gameplay/animation/etc. objects

sf.objects.GameObject = {
    moveBy: function(x, y, holdPrev) {
        this.calculateBounds();
        if (this.movable) {
            if (!holdPrev) {
                this.prevpos.x = this.pos.x;
                this.prevpos.y = this.pos.y;
            }
            this.pos.x = this.pos.x + x;
            this.pos.y = this.pos.y + y;
            this.calculateBounds();
        }
    },
    moveBack: function() {
        this.pos.x = this.prevpos.x;
        this.pos.y = this.prevpos.y;
        this.calculateBounds();
    },
    calculateBounds: function() {

        this.bounds.top = this.pos.y - (this.outerheight/2);
        this.bounds.left = this.pos.x - (this.outerwidth/2);
        this.bounds.bottom = this.pos.y + (this.outerheight/2);
        this.bounds.right = this.pos.x + (this.outerwidth/2);

        this.prevbounds.top = this.prevpos.y - (this.outerheight/2);
        this.prevbounds.left = this.prevpos.x - (this.outerwidth/2);
        this.prevbounds.bottom = this.prevpos.y + (this.outerheight/2);
        this.prevbounds.right = this.prevpos.x + (this.outerwidth/2);

        // For some aggressive optimization of collision detection...
        this.movebounds.top = (this.bounds.top < this.prevbounds.top) ? this.bounds.top : this.prevbounds.top;
        this.movebounds.left = (this.bounds.left < this.prevbounds.left) ? this.bounds.left : this.prevbounds.left;
        this.movebounds.bottom = (this.bounds.bottom > this.prevbounds.bottom) ? this.bounds.bottom : this.prevbounds.bottom;
        this.movebounds.right = (this.bounds.right > this.prevbounds.right) ? this.bounds.right : this.prevbounds.right;
        if (this.movebounds.right <= this.movebounds.left || this.movebounds.bottom <= this.movebounds.top) {
            console.log('STUFF SERIOUSLY WRONG, movebounds:', this.movebounds)
        }

    },
    areaCollision: function(that) { // This collision detection is for first pruning of cases.
        if (this.movebounds.right > that.movebounds.left &&
            that.movebounds.right > this.movebounds.left &&
            this.movebounds.bottom > that.movebounds.top &&
            that.movebounds.bottom > this.movebounds.top) {
            return true;
        }
        else {
            // console.log(this, that);
            return false;
        }
    },
    crudeCollision: function(that) { // This collision detection is for simple cases. Only run after getting true from areaCollision!
        return true; // doesn't do anything really yet...
    },
    hitboxCollision: function(that) { // this collision function is for most definite cases. Only run after getting true from crudeCollision!
        return true; // doesn't do anything really yet...
    },
    collision: function(that) { // Remember to run calculateBounds for both this and that before asking collision!
        //console.log('Calling collision!');
        return (this.areaCollision(that) && this.crudeCollision(that) && this.hitboxCollision(that));
    },
    arrayCollision: function(arrayOfThats) {
        for (var i=0; i<arrayOfThats.length; i++) {
            if (this.collision(arrayOfThats[i])) {
                return true;
            }
        }
        return false;
    },
    init: function(posX, posY, movable, outerwidth, outerheight, blocking) {
        this.pos = {x: posX, y: posY };
        this.prevpos = {x: posX, y: posY };
        this.movable = movable;
        this.outerwidth = outerwidth;
        this.outerheight= outerheight;
        this.bounds = {};
        this.prevbounds = {};
        this.movebounds = {};
        this.calculateBounds();
        this.active = false;
        if (typeof blocking === 'undefined') {this.blocking = false;}
        else {this.blocking = blocking;}
        this.color = 'rgb(0,0,0)';
    },
    draw: function(context, drawColor) {
        if (typeof drawColor === 'undefined') {var drawColor=this.color;}
        if (!this.sprite) {
            context.fillStyle=drawColor;
            context.fillRect(this.bounds.left, this.bounds.top, this.outerwidth, this.outerheight);
        }
    },
    tick: function() { // overwrite this function for objects that that actually do something.
    },
    shoutInfo: function() {
        console.log(this);
    }
};

<|endoftext|>


<commit_before>import React from 'react'

const Form = props => (

Please complete order details:

    <form label="shippingAddress">
      <input name ="address" placeholder="Street Address" />
      <input name ="city" placeholder="City" />
      <input name ="state" placeholder="State" />
      <input name ="zip code" placeholder="Zip Code" />
      <input name ="email" placeholder="Please confirm email" />
    </form>

)

export default Form
<commit_msg>feat(checkout): added schema and form component<commit_after>import React from 'react'

const Form = props => (

Please complete order details:

    <form label="shippingAddress">
      <input name ="address" placeholder="Street Address" />
      <input name ="city" placeholder="City" />
      <input name ="state" placeholder="State" />
      <input name ="zip code" placeholder="Zip Code" />
      <input name ="email" placeholder="Please confirm email" />
    </form>

)

export default Form
<|endoftext|>


<commit_before>// Copyright 2002-2013, University of Colorado Boulder

/**
 * NumberProperty extends Property<Number> and adds functions specific to numbers, such as <, >.
 * TODO: Let's discuss creating these automatically in PropertySets
 *
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  var axon = require( 'AXON/axon' );
  var Property = require( 'AXON/Property' );
  var DerivedProperty = require( 'AXON/DerivedProperty' );
  var inherit = require( 'PHET_CORE/inherit' );

  //See http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric
  function isNumber( n ) {
    return !isNaN( parseFloat( n ) ) && isFinite( n );
  }

  /**
   * @param {number} value
   * @constructor
   */
  axon.NumberProperty = function NumberProperty( value ) {
    assert && assert( isNumber( value ) );
    axon.Property.call( this, value );
  };

  return inherit( axon.Property, axon.NumberProperty, {
    lessThanNumber: function( number ) {
      return new DerivedProperty( [this], function( thisValue ) { return thisValue < number; } );
    },
    greaterThanNumber: function( number ) {
      return new DerivedProperty( [this], function( thisValue ) { return thisValue > number; } );
    }
  } );
} );<commit_msg>Removed unused vars<commit_after>// Copyright 2002-2013, University of Colorado Boulder

/**
 * NumberProperty extends Property<Number> and adds functions specific to numbers, such as <, >.
 * TODO: Let's discuss creating these automatically in PropertySets
 *
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  var axon = require( 'AXON/axon' );
  var DerivedProperty = require( 'AXON/DerivedProperty' );
  var inherit = require( 'PHET_CORE/inherit' );

  //See http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric
  function isNumber( n ) {
    return !isNaN( parseFloat( n ) ) && isFinite( n );
  }

  /**
   * @param {number} value
   * @constructor
   */
  axon.NumberProperty = function NumberProperty( value ) {
    assert && assert( isNumber( value ) );
    axon.Property.call( this, value );
  };

  return inherit( axon.Property, axon.NumberProperty, {
    lessThanNumber: function( number ) {
      return new DerivedProperty( [this], function( thisValue ) { return thisValue < number; } );
    },
    greaterThanNumber: function( number ) {
      return new DerivedProperty( [this], function( thisValue ) { return thisValue > number; } );
    }
  } );
} );<|endoftext|>


<commit_before>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    var move;
    return move || getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
	var move;
    return move || randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    if (playerMove === computerMove) {
    	winner = 'tie';
    } else if (playerMove === 'rock') {
    	if (computerMove === 'paper') {
    		winner = 'computer';
    	} else {
    		winner = 'player';
    	}
    } else if (playerMove === 'paper') {
    	if (computerMove === 'scissors') {
    		winner = 'computer';
    	} else {
    		winner = 'player';
    	}
    } else if (playerMove === 'scissors') {
    	if (computerMove === 'rock') {
    		winner = 'computer';
    	} else {
    		winner = 'player';
    	}
    }

    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.
    /* YOUR CODE HERE */
    return [playerWins, computerWins];
}

<commit_msg>Saving all changes before final debugging<commit_after>////////////////////////////////////////////////
/*   Provided Code - Please Don't Edit   */
////////////////////////////////////////////////
'use strict';

function getInput() {
    console.log("Please choose either 'rock', 'paper', or 'scissors'.")
    return prompt();
}
function randomPlay() {
    var randomNumber = Math.random();
    if (randomNumber < 0.33) {
        return "rock";
    } else if (randomNumber < 0.66) {
        return "paper";
    } else {
        return "scissors";
    }
}
////////////////////////////////////////////////
/*           Write Your Code Below            */
////////////////////////////////////////////////

function getPlayerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `getInput()`.
    return move || getInput();
}

function getComputerMove(move) {
    // Write an expression that operates on a variable called `move`
    // If a `move` has a value, your expression should evaluate to that value.
    // However, if `move` is not specified / is null, your expression should equal `randomPlay()`.
    return move || randomPlay();
}

function getWinner(playerMove,computerMove) {
    var winner;
    // Write code that will set winner to either 'player', 'computer', or 'tie' based on the values of playerMove and computerMove.
    // Assume that the only values playerMove and computerMove can have are 'rock', 'paper', and 'scissors'.
    // The rules of the game are that 'rock' beats 'scissors', 'scissors' beats 'paper', and 'paper' beats 'rock'.
    if (playerMove === computerMove) {
    	winner = 'tie';
    } else if (playerMove === 'rock') {
    	if (computerMove === 'paper') {
    		winner = 'computer';
    	} else {
    		winner = 'player';
    	}
    } else if (playerMove === 'paper') {
    	if (computerMove === 'scissors') {
    		winner = 'computer';
    	} else {
    		winner = 'player';
    	}
    } else if (playerMove === 'scissors') {
    	if (computerMove === 'rock') {
    		winner = 'computer';
    	} else {
    		winner = 'player';
    	}
    }

    return winner;
}

function playToFive() {
    console.log("Let's play Rock, Paper, Scissors");
    var playerWins = 0;
    var computerWins = 0;
    // Write code that plays 'Rock, Paper, Scissors' until either the player or the computer has won five times.

    while (playerWins < 5 && computerWins <5) {

        var playerMove = getPlayerMove();
        var computerMove = getComputerMove();
    	var winner = getWinner(playerMove, computerMove);

    	if (winner = 'player') {
    		playerWins ++;
    	} else if (winner = 'computer') {
    		computerWins ++;
    	}

        console.log("Player chose " + playerMove + " while Computer chose " + computerMove + " so " + winner + " wins.");

        console.log("The current score is " + "Player: " + playerWins + " to Computer: " + computerWins);
    }

    return [playerWins, computerWins];
}

playToFive();<|endoftext|>


<commit_before>compiler.mode.link = def(
  [
    compiler.tools.error,
    compiler.tools.io,
    compiler.bootstrap.generator,
    compiler.compile.configurator,
    compiler.meta.metalator,
    ephox.bolt.kernel.fp.array,
    require('path')
  ],

  function (error, io, generator, configurator, metalator, ar, path) {

    var slurp = function (file) {
      if (!metalator.hasMetadata(file))
        error.die('no meta-data found for file, "' + file + '", can only link compile output');
      var defines = metalator.inspect(file);
      return {file: file, defines: defines};
    };

    var configthing = function (bit) {
      var defines = bit.defines;
      var filepath = bit.file;
      var name = path.basename(filepath, '.js');
      return defines.map(function (define) {
        return 'source("amd", "' + define + '", ".", mapper.constant("' + name + '"))';
      });
    };

    var install =
      '(function () {\n' +
      '  var pather = ephox.bolt.module.bootstrap.pather;\n' +
      '  var install = ephox.bolt.module.bootstrap.install;\n' +
      '  install.install(pather.compile());\n' +
      '})();';

    var link = function (files) {
      var bits = files.map(slurp);
      return ar.flatmap(bits, configthing);
    };

    var run = function (config /*, files, target */) {
      var rest = Array.prototype.slice.call(arguments, 1);
      var files = rest.slice(0, -1);
      var target = rest[rest.length - 1];
      var parts = link(files);
      var sources = parts.join(',\n    ');

      var configuration =
        '(function () {\n' +
        '  var configure = ephox.bolt.module.api.configure;\n' +
        '  var source = ephox.bolt.module.api.source;\n' +
        '  var mapper = ephox.bolt.module.api.mapper;\n' +
        '  configure({' +
        '    sources: [\n' +
        '    ' + sources + '\n' +
        '    ]' +
          '});\n' +
        '})()';

      generator.generate(target, install + '\n' + configuration);
    };

    return {
      run: run
    };
  }
);
<commit_msg>Add missing semi-colon. Oops<commit_after>compiler.mode.link = def(
  [
    compiler.tools.error,
    compiler.tools.io,
    compiler.bootstrap.generator,
    compiler.compile.configurator,
    compiler.meta.metalator,
    ephox.bolt.kernel.fp.array,
    require('path')
  ],

  function (error, io, generator, configurator, metalator, ar, path) {

    var slurp = function (file) {
      if (!metalator.hasMetadata(file))
        error.die('no meta-data found for file, "' + file + '", can only link compile output');
      var defines = metalator.inspect(file);
      return {file: file, defines: defines};
    };

    var configthing = function (bit) {
      var defines = bit.defines;
      var filepath = bit.file;
      var name = path.basename(filepath, '.js');
      return defines.map(function (define) {
        return 'source("amd", "' + define + '", ".", mapper.constant("' + name + '"))';
      });
    };

    var install =
      '(function () {\n' +
      '  var pather = ephox.bolt.module.bootstrap.pather;\n' +
      '  var install = ephox.bolt.module.bootstrap.install;\n' +
      '  install.install(pather.compile());\n' +
      '})();';

    var link = function (files) {
      var bits = files.map(slurp);
      return ar.flatmap(bits, configthing);
    };

    var run = function (config /*, files, target */) {
      var rest = Array.prototype.slice.call(arguments, 1);
      var files = rest.slice(0, -1);
      var target = rest[rest.length - 1];
      var parts = link(files);
      var sources = parts.join(',\n    ');

      var configuration =
        '(function () {\n' +
        '  var configure = ephox.bolt.module.api.configure;\n' +
        '  var source = ephox.bolt.module.api.source;\n' +
        '  var mapper = ephox.bolt.module.api.mapper;\n' +
        '  configure({' +
        '    sources: [\n' +
        '    ' + sources + '\n' +
        '    ]' +
          '});\n' +
        '})();';

      generator.generate(target, install + '\n' + configuration);
    };

    return {
      run: run
    };
  }
);
<|endoftext|>


<commit_before>
var getLagLng = function(){
  var lat = 0;
  var lng = 0;
  if(navigation.geolocation){
    navigator.geolocation.getCurrentPosition(function(pos){
      lat = pos.coords.latitude;
      lng = pos.coords.longitude;
    });
  }
  return {lat:lat,lng:lng};
};

var init = function(){
  console.log("geocacher.js - init");
  var latlng = getLatLng();

  console.log("Current Location: " + latlng.lat + ", " + latlng.lng);
};

exports.getLatLng = this.getLatLng;
init();
<commit_msg>Using a callback to handle what I get back from lat/lng - just outputting to console<commit_after>
var getLatLng = function(callback){
  if(navigator.geolocation){
    navigator.geolocation.getCurrentPosition(function(pos){
      callback.apply(pos,[pos.coords.latitude,pos.coords.longitude]);
    });
  }
};

var init = function(){
  console.log("geocacher.js - init");
  getLatLng(outputLatLngToConsole);
};
var outputLatLngToConsole = function(lat,lng){
  console.log("Lat: " + lat);
  console.log("Lng: " + lng);
};

exports.getLatLng = this.getLatLng;
init();
<|endoftext|>


<commit_before>function setupFlorence() {
    websocket.open();
    log.add(log.eventTypes.appInitialised);

    window.templates = Handlebars.templates;
    Handlebars.registerPartial("browseNode", templates.browseNode);
    Handlebars.registerPartial("editNav", templates.editNav);
    Handlebars.registerPartial("editNavChild", templates.editNavChild);
    Handlebars.registerPartial("selectorHour", templates.selectorHour);
    Handlebars.registerPartial("selectorMinute", templates.selectorMinute);
    Handlebars.registerPartial("tickAnimation", templates.tickAnimation);
    Handlebars.registerPartial("loadingAnimation", templates.loadingAnimation);
    Handlebars.registerPartial("childDeletes", templates.childDeletes);
    Handlebars.registerHelper('select', function (value, options) {
        var $el = $('<select />').html(options.fn(this));
        $el.find('[value="' + value + '"]').attr({'selected': 'selected'});
        return $el.html();
    });
    Handlebars.registerHelper('ifCond', function (v1, operator, v2, options) {

        switch (operator) {
            case '==':
                return (v1 == v2) ? options.fn(this) : options.inverse(this);
            case '===':
                return (v1 === v2) ? options.fn(this) : options.inverse(this);
            case '<':
                return (v1 < v2) ? options.fn(this) : options.inverse(this);
            case '<=':
                return (v1 <= v2) ? options.fn(this) : options.inverse(this);
            case '>':
                return (v1 > v2) ? options.fn(this) : options.inverse(this);
            case '>=':
                return (v1 >= v2) ? options.fn(this) : options.inverse(this);
            case '&&':
                return (v1 && v2) ? options.fn(this) : options.inverse(this);
            case '||':
                return (v1 || v2) ? options.fn(this) : options.inverse(this);
            default:
                return options.inverse(this);
        }
    });
    //Check if array contains element
    Handlebars.registerHelper('ifContains', function (elem, list, options) {
        if (list.indexOf(elem) > -1) {
            return options.fn(this);
        }
        return options.inverse(this);
    });
    // Add two values together. Primary usage was '@index + 1' to create numbered lists
    Handlebars.registerHelper('plus', function (value1, value2) {
        return value1 + value2;
    });
    // Add two values together. Primary usage was '@index + 1' to create numbered lists
    Handlebars.registerHelper('lastEditedBy', function (array) {
        if (array) {
            var event = array[array.length - 1];
            if (event) {
                return 'Last edited ' + StringUtils.formatIsoDateString(new Date(event.date)) + " by " + event.email;
            }
        }
        return '';
    });
    Handlebars.registerHelper('createdBy', function (array) {
        if (array) {
            var event = getCollectionCreatedEvent(array);
            if (event) {
                return 'Created ' + StringUtils.formatIsoDateString(new Date(event.date)) + " by " + event.email + '';
            } else {
                return "";
            }
        }
        return "";
    });
    // If two strings match
    Handlebars.registerHelper('if_eq', function (a, b, opts) {
        if (a == b)
            return opts.fn(this);
        else
            return opts.inverse(this);
    });
    // If two strings don't match
    Handlebars.registerHelper('if_ne', function (a, b, opts) {
        if (a != b)
            return opts.fn(this);
        else
            return opts.inverse(this);
    });

    Handlebars.registerHelper('comma_separated_list', function (array) {
        var asString = "";

        if (array) {
            array.forEach(function (item) {
                asString = asString + item + ", ";
            });
            return asString.substring(0, asString.lastIndexOf(","));
        }
        return asString;
    });

    Handlebars.registerHelper('parent_dir', function (uri) {
        var pathSections = uri.split("/");
        if (pathSections.length > 0) {
            return "/" + pathSections[pathSections.length -1];
        }
        return "";
    });

    Handlebars.registerHelper('debug', function (message, object) {
        console.log("DEBUG: " + message + " " + JSON.stringify(object));
        return "";
    });

    Florence.globalVars.activeTab = false;

    // load main florence template
    var florence = templates.florence;

    $('body').append(florence);
    Florence.refreshAdminMenu();

    var adminMenu = $('.js-nav');
    // dirty checks on admin menu
    adminMenu.on('click', '.js-nav-item', function () {
        if (Florence.Editor.isDirty) {
            swal({
                title: "Warning",
                text: "If you do not come back to this page, you will lose any unsaved changes",
                type: "warning",
                showCancelButton: true,
                confirmButtonText: "Continue",
                cancelButtonText: "Cancel"
            }, function (result) {
                if (result === true) {
                    Florence.Editor.isDirty = false;
                    processMenuClick(this);
                    return true;
                } else {
                    return false;
                }
            });
        } else {
            processMenuClick(this);
        }
    });

    window.onbeforeunload = function () {
        if (Florence.Editor.isDirty) {
            return 'You have unsaved changes.';
        }
    };

    var path = (location.pathname).replace('/florence/', '');
    function mapPathToViewID(path) {
        if (!path || path === '/florence') {
            return "collections";
        }
        return {
            "collections": "collections",
            "publishing-queue": "publish",
            "reports": "reports",
            "users-and-access": "users",
            "workspace": "workspace"
        }[path];
    };
    $('.js-nav-item--' + mapPathToViewID(path)).addClass('selected');
    viewController(mapPathToViewID(path));

    window.onpopstate = function() {
        var newPath = (document.location.pathname).replace('/florence/', '');
        $('.js-nav-item--collection').hide();
        $('.js-nav-item').removeClass('selected');
        $('.js-nav-item--' + mapPathToViewID(newPath)).addClass('selected');
        viewController(mapPathToViewID(newPath));
    }

    function processMenuClick(clicked) {
        Florence.collection = {};

        $('.js-nav-item--collection').hide();
        $('.js-nav-item').removeClass('selected');
        var menuItem = $(clicked);

        menuItem.addClass('selected');

        if (menuItem.hasClass("js-nav-item--collections")) {
            window.history.pushState({}, "", "/florence/collections")
            viewController('collections');
        } else if (menuItem.hasClass("js-nav-item--collection")) {
            var thisCollection = CookieUtils.getCookieValue("collection");
            window.history.pushState({}, "", "/florence/collections")
            viewCollections(thisCollection);
            $(".js-nav-item--collections").addClass('selected');
        } else if (menuItem.hasClass("js-nav-item--users")) {
            window.history.pushState({}, "", "/florence/users-and-access");
            viewController('users');
        } else if (menuItem.hasClass("js-nav-item--teams")) {
            window.history.pushState({}, "", "/florence/teams");
            viewController('teams');
        } else if (menuItem.hasClass("js-nav-item--publish")) {
            window.history.pushState({}, "", "/florence/publishing-queue");
            viewController('publish');
        } else if (menuItem.hasClass("js-nav-item--reports")) {
            window.history.pushState({}, "", "/florence/reports");
            viewController('reports');
        } else if (menuItem.hasClass("js-nav-item--login")) {
            viewController('login');
        } else if (menuItem.hasClass("js-nav-item--logout")) {
            logout();
            viewController();
        }
    }

    // redirect a viewer to not authorised message if they try access old Florence
    var userType = localStorage.getItem("userType");
    if (userType == "VIEWER") {
        window.location.href = '/florence/not-authorised';
    }

    // Get ping times to zebedee and surface for user
    var lastPingTime;
    var pingTimes = [];

    function doPing() {
        var start = performance.now();
        $.ajax({
            url: "/zebedee/ping",
            dataType: 'json',
            contentType: 'application/json',
            type: 'POST',
            data: JSON.stringify({
                lastPingTime: lastPingTime
            }),
            success: function (response) {

                // Handle session information
                checkSessionTimeout(response);

                var end = performance.now();
                var time = Math.round(end - start);

                lastPingTime = time;

                networkStatus(lastPingTime);

                Florence.ping.add(time)

                pingTimer = setTimeout(function () {
                    doPing();
                }, 10000);
            },
            error: function() {
                Florence.ping.add(0);
                console.error("Error during POST to ping endpoint on Zebedee");
                pingTimer = setTimeout(function () {
                    doPing();
                }, 10000);
            }
        });
    }

    var pingTimer = setTimeout(function () {
        doPing();
    }, 10000);

    // Alert user if ping states that their session is going to log out (log out if it's run out too)
    var countdownIsShown = false,
        secondCounter = 0;

    function checkSessionTimeout(sessionData) {
        var currentDateTime = new Date(),
            sessionExpiry = new Date(sessionData.sessionExpiryDate),
            timeLeftInSession = parseInt((sessionExpiry - currentDateTime)/1000);

        if (timeLeftInSession <= 31 && !countdownIsShown) {
            // Session is going to expire soon, warn user and give them option to reset session timer
            countdownIsShown = true;
            secondCounter = timeLeftInSession;
            console.log("Session to expire in " + timeLeftInSession + " seconds");
            sweetAlert({
                type: "warning",
                title: "Session expiring in " + timeLeftInSession + " seconds",
                text: "You've not been active for sometime now, are you still using Florence?",
                html: true,
                confirmButtonText: "I'm still using Florence!"
            }, function(response) {
                if (response) {
                    $.get("/zebedee/users?email=" + Florence.Authentication.loggedInEmail());
                    countdownIsShown = false;
                    console.log("Session timer reset");
                }
            });
            // Update alert with amount of time user has left until they're logged out
            var sessionCountdown = setInterval(function() {
                secondCounter -= 1;
                $('#session-expiry').html(secondCounter);

                // If session has timed out & the warning hasn't been closed yet, log out the user and inform them why they've been logged out
                if (secondCounter === 0 && countdownIsShown) {
                    sweetAlert({
                        type: "warning",
                        title: "Your session has expired",
                        text: "Florence was left inactive for too long so you have been logged out"
                    });
                    logout();
                    countdownIsShown = false;
                    clearInterval(sessionCountdown);
                } else if (!countdownIsShown) {
                    // User responded to warning so Florence is active now, clear the countdown
                    clearInterval(sessionCountdown);
                }
            }, 1000);
        }
    }

    // Reset default functions from certain elements - eg form submits
    resetPage();

    // Log every click that will be changing the state or data in Florence
    $(document).on('click', 'a, button, input[type="button"], iframe, .table--primary tr, .js-nav-item, .page__item', function(e) {
        var diagnosticJSON = JSON.stringify(new clickEventObject(e));
        $.ajax({
            url: "/zebedee/clickEventLog",
            type: 'POST',
            contentType: "application/json",
            data: diagnosticJSON,
            async: true,
        });
    });

    function clickEventObject(event) {
        this.user = localStorage.getItem('loggedInAs');
        triggerTemp = {};
        collectionTemp = {};

        if (event.target.id) {
            triggerTemp.elementId = event.target.id;
        }

        if ($(event.target).attr('class')) {
            classes = [];
            $.each($(event.target).attr('class').split(" "), function(index, value) {
                if (value) {
                    classes.push(value);
                }
            });
            if (classes.length > 0) {
                triggerTemp.elementClasses = classes;
            }
        }

        if (Florence.collection.id) {
            collectionTemp.id = Florence.collection.id;
        }

        if (Florence.collection.name) {
            collectionTemp.name = Florence.collection.name;
        }

        if (Florence.collection.type) {
            collectionTemp.type = Florence.collection.type;
        }

        if (triggerTemp.elementId || triggerTemp.elementClasses) {
            this.trigger = triggerTemp;
        }

        if (collectionTemp.id || collectionTemp.name || collectionTemp.type) {
            this.collection = collectionTemp
        }
    }

    // Check running version versus latest and notify user if they don't match
    var runningVersion,
        userWarned = false;
    function checkVersion() {
        return fetch('/florence/dist/legacy-assets/version.json')
            .then(function(response) {
                return response.json();
            })
            .then(function(responseJson) {
                return responseJson;
            })
            .catch(function(err) {
                console.log("Error getting latest Florence version: ", err);
                return err
            });
    }

    checkVersion().then(function(response) {
        runningVersion = response;
    });

}

<commit_msg>removed all Feature/version-reloading<commit_after>function setupFlorence() {
    websocket.open();
    log.add(log.eventTypes.appInitialised);

    window.templates = Handlebars.templates;
    Handlebars.registerPartial("browseNode", templates.browseNode);
    Handlebars.registerPartial("editNav", templates.editNav);
    Handlebars.registerPartial("editNavChild", templates.editNavChild);
    Handlebars.registerPartial("selectorHour", templates.selectorHour);
    Handlebars.registerPartial("selectorMinute", templates.selectorMinute);
    Handlebars.registerPartial("tickAnimation", templates.tickAnimation);
    Handlebars.registerPartial("loadingAnimation", templates.loadingAnimation);
    Handlebars.registerPartial("childDeletes", templates.childDeletes);
    Handlebars.registerHelper('select', function (value, options) {
        var $el = $('<select />').html(options.fn(this));
        $el.find('[value="' + value + '"]').attr({'selected': 'selected'});
        return $el.html();
    });
    Handlebars.registerHelper('ifCond', function (v1, operator, v2, options) {

        switch (operator) {
            case '==':
                return (v1 == v2) ? options.fn(this) : options.inverse(this);
            case '===':
                return (v1 === v2) ? options.fn(this) : options.inverse(this);
            case '<':
                return (v1 < v2) ? options.fn(this) : options.inverse(this);
            case '<=':
                return (v1 <= v2) ? options.fn(this) : options.inverse(this);
            case '>':
                return (v1 > v2) ? options.fn(this) : options.inverse(this);
            case '>=':
                return (v1 >= v2) ? options.fn(this) : options.inverse(this);
            case '&&':
                return (v1 && v2) ? options.fn(this) : options.inverse(this);
            case '||':
                return (v1 || v2) ? options.fn(this) : options.inverse(this);
            default:
                return options.inverse(this);
        }
    });
    //Check if array contains element
    Handlebars.registerHelper('ifContains', function (elem, list, options) {
        if (list.indexOf(elem) > -1) {
            return options.fn(this);
        }
        return options.inverse(this);
    });
    // Add two values together. Primary usage was '@index + 1' to create numbered lists
    Handlebars.registerHelper('plus', function (value1, value2) {
        return value1 + value2;
    });
    // Add two values together. Primary usage was '@index + 1' to create numbered lists
    Handlebars.registerHelper('lastEditedBy', function (array) {
        if (array) {
            var event = array[array.length - 1];
            if (event) {
                return 'Last edited ' + StringUtils.formatIsoDateString(new Date(event.date)) + " by " + event.email;
            }
        }
        return '';
    });
    Handlebars.registerHelper('createdBy', function (array) {
        if (array) {
            var event = getCollectionCreatedEvent(array);
            if (event) {
                return 'Created ' + StringUtils.formatIsoDateString(new Date(event.date)) + " by " + event.email + '';
            } else {
                return "";
            }
        }
        return "";
    });
    // If two strings match
    Handlebars.registerHelper('if_eq', function (a, b, opts) {
        if (a == b)
            return opts.fn(this);
        else
            return opts.inverse(this);
    });
    // If two strings don't match
    Handlebars.registerHelper('if_ne', function (a, b, opts) {
        if (a != b)
            return opts.fn(this);
        else
            return opts.inverse(this);
    });

    Handlebars.registerHelper('comma_separated_list', function (array) {
        var asString = "";

        if (array) {
            array.forEach(function (item) {
                asString = asString + item + ", ";
            });
            return asString.substring(0, asString.lastIndexOf(","));
        }
        return asString;
    });

    Handlebars.registerHelper('parent_dir', function (uri) {
        var pathSections = uri.split("/");
        if (pathSections.length > 0) {
            return "/" + pathSections[pathSections.length -1];
        }
        return "";
    });

    Handlebars.registerHelper('debug', function (message, object) {
        console.log("DEBUG: " + message + " " + JSON.stringify(object));
        return "";
    });

    Florence.globalVars.activeTab = false;

    // load main florence template
    var florence = templates.florence;

    $('body').append(florence);
    Florence.refreshAdminMenu();

    var adminMenu = $('.js-nav');
    // dirty checks on admin menu
    adminMenu.on('click', '.js-nav-item', function () {
        if (Florence.Editor.isDirty) {
            swal({
                title: "Warning",
                text: "If you do not come back to this page, you will lose any unsaved changes",
                type: "warning",
                showCancelButton: true,
                confirmButtonText: "Continue",
                cancelButtonText: "Cancel"
            }, function (result) {
                if (result === true) {
                    Florence.Editor.isDirty = false;
                    processMenuClick(this);
                    return true;
                } else {
                    return false;
                }
            });
        } else {
            processMenuClick(this);
        }
    });

    window.onbeforeunload = function () {
        if (Florence.Editor.isDirty) {
            return 'You have unsaved changes.';
        }
    };

    var path = (location.pathname).replace('/florence/', '');
    function mapPathToViewID(path) {
        if (!path || path === '/florence') {
            return "collections";
        }
        return {
            "collections": "collections",
            "publishing-queue": "publish",
            "reports": "reports",
            "users-and-access": "users",
            "workspace": "workspace"
        }[path];
    };
    $('.js-nav-item--' + mapPathToViewID(path)).addClass('selected');
    viewController(mapPathToViewID(path));

    window.onpopstate = function() {
        var newPath = (document.location.pathname).replace('/florence/', '');
        $('.js-nav-item--collection').hide();
        $('.js-nav-item').removeClass('selected');
        $('.js-nav-item--' + mapPathToViewID(newPath)).addClass('selected');
        viewController(mapPathToViewID(newPath));
    }

    function processMenuClick(clicked) {
        Florence.collection = {};

        $('.js-nav-item--collection').hide();
        $('.js-nav-item').removeClass('selected');
        var menuItem = $(clicked);

        menuItem.addClass('selected');

        if (menuItem.hasClass("js-nav-item--collections")) {
            window.history.pushState({}, "", "/florence/collections")
            viewController('collections');
        } else if (menuItem.hasClass("js-nav-item--collection")) {
            var thisCollection = CookieUtils.getCookieValue("collection");
            window.history.pushState({}, "", "/florence/collections")
            viewCollections(thisCollection);
            $(".js-nav-item--collections").addClass('selected');
        } else if (menuItem.hasClass("js-nav-item--users")) {
            window.history.pushState({}, "", "/florence/users-and-access");
            viewController('users');
        } else if (menuItem.hasClass("js-nav-item--teams")) {
            window.history.pushState({}, "", "/florence/teams");
            viewController('teams');
        } else if (menuItem.hasClass("js-nav-item--publish")) {
            window.history.pushState({}, "", "/florence/publishing-queue");
            viewController('publish');
        } else if (menuItem.hasClass("js-nav-item--reports")) {
            window.history.pushState({}, "", "/florence/reports");
            viewController('reports');
        } else if (menuItem.hasClass("js-nav-item--login")) {
            viewController('login');
        } else if (menuItem.hasClass("js-nav-item--logout")) {
            logout();
            viewController();
        }
    }

    // redirect a viewer to not authorised message if they try access old Florence
    var userType = localStorage.getItem("userType");
    if (userType == "VIEWER") {
        window.location.href = '/florence/not-authorised';
    }

    // Get ping times to zebedee and surface for user
    var lastPingTime;
    var pingTimes = [];

    function doPing() {
        var start = performance.now();
        $.ajax({
            url: "/zebedee/ping",
            dataType: 'json',
            contentType: 'application/json',
            type: 'POST',
            data: JSON.stringify({
                lastPingTime: lastPingTime
            }),
            success: function (response) {

                // Handle session information
                checkSessionTimeout(response);

                var end = performance.now();
                var time = Math.round(end - start);

                lastPingTime = time;

                networkStatus(lastPingTime);

                Florence.ping.add(time)

                pingTimer = setTimeout(function () {
                    doPing();
                }, 10000);
            },
            error: function() {
                Florence.ping.add(0);
                console.error("Error during POST to ping endpoint on Zebedee");
                pingTimer = setTimeout(function () {
                    doPing();
                }, 10000);
            }
        });
    }

    var pingTimer = setTimeout(function () {
        doPing();
    }, 10000);

    // Alert user if ping states that their session is going to log out (log out if it's run out too)
    var countdownIsShown = false,
        secondCounter = 0;

    function checkSessionTimeout(sessionData) {
        var currentDateTime = new Date(),
            sessionExpiry = new Date(sessionData.sessionExpiryDate),
            timeLeftInSession = parseInt((sessionExpiry - currentDateTime)/1000);

        if (timeLeftInSession <= 31 && !countdownIsShown) {
            // Session is going to expire soon, warn user and give them option to reset session timer
            countdownIsShown = true;
            secondCounter = timeLeftInSession;
            console.log("Session to expire in " + timeLeftInSession + " seconds");
            sweetAlert({
                type: "warning",
                title: "Session expiring in " + timeLeftInSession + " seconds",
                text: "You've not been active for sometime now, are you still using Florence?",
                html: true,
                confirmButtonText: "I'm still using Florence!"
            }, function(response) {
                if (response) {
                    $.get("/zebedee/users?email=" + Florence.Authentication.loggedInEmail());
                    countdownIsShown = false;
                    console.log("Session timer reset");
                }
            });
            // Update alert with amount of time user has left until they're logged out
            var sessionCountdown = setInterval(function() {
                secondCounter -= 1;
                $('#session-expiry').html(secondCounter);

                // If session has timed out & the warning hasn't been closed yet, log out the user and inform them why they've been logged out
                if (secondCounter === 0 && countdownIsShown) {
                    sweetAlert({
                        type: "warning",
                        title: "Your session has expired",
                        text: "Florence was left inactive for too long so you have been logged out"
                    });
                    logout();
                    countdownIsShown = false;
                    clearInterval(sessionCountdown);
                } else if (!countdownIsShown) {
                    // User responded to warning so Florence is active now, clear the countdown
                    clearInterval(sessionCountdown);
                }
            }, 1000);
        }
    }

    // Reset default functions from certain elements - eg form submits
    resetPage();

    // Log every click that will be changing the state or data in Florence
    $(document).on('click', 'a, button, input[type="button"], iframe, .table--primary tr, .js-nav-item, .page__item', function(e) {
        var diagnosticJSON = JSON.stringify(new clickEventObject(e));
        $.ajax({
            url: "/zebedee/clickEventLog",
            type: 'POST',
            contentType: "application/json",
            data: diagnosticJSON,
            async: true,
        });
    });

    function clickEventObject(event) {
        this.user = localStorage.getItem('loggedInAs');
        triggerTemp = {};
        collectionTemp = {};

        if (event.target.id) {
            triggerTemp.elementId = event.target.id;
        }

        if ($(event.target).attr('class')) {
            classes = [];
            $.each($(event.target).attr('class').split(" "), function(index, value) {
                if (value) {
                    classes.push(value);
                }
            });
            if (classes.length > 0) {
                triggerTemp.elementClasses = classes;
            }
        }

        if (Florence.collection.id) {
            collectionTemp.id = Florence.collection.id;
        }

        if (Florence.collection.name) {
            collectionTemp.name = Florence.collection.name;
        }

        if (Florence.collection.type) {
            collectionTemp.type = Florence.collection.type;
        }

        if (triggerTemp.elementId || triggerTemp.elementClasses) {
            this.trigger = triggerTemp;
        }

        if (collectionTemp.id || collectionTemp.name || collectionTemp.type) {
            this.collection = collectionTemp
        }
    }
}

<|endoftext|>