<commit_before>exports.level = {
  "name": {
    "en_US": "Introduction to Git Commits",
    "fr_FR": "Introduction aux commits avec Git",
    'ko': 'Git 커밋 소개'
  },
  "goalTreeString": "{\"branches\":{\"master\":{\"target\":\"C3\",\"id\":\"master\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C2\"],\"id\":\"C3\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
  "solutionCommand": "git commit;git commit",
  "startTree": "{\"branches\":{\"master\":{\"target\":\"C1\",\"id\":\"master\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
  "hint": {
    "en_US": "Just type in 'git commit' twice to finish!",
    "fr_FR": "Il suffit de saisir 'git commit' deux fois pour réussir !",
    "zh_CN": "敲两次 'git commit' 就好啦！",
    "ko": "'git commit'이라고 두 번 치세요!"
  },
  "disabledMap": {
    "git revert": true
  },
  "startDialog": {
    "en_US": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "## Git Commits",
              "A commit in a git repository records a snapshot of all the files in your directory. It's like a giant copy and paste, but even better!",
              "",
              "Git wants to keep commits as lightweight as possible though, so it doesn't just copy the entire directory every time you commit. It actually stores each commit as a set of changes, or a \"delta\", from one version of the repository to the next. That's why most commits have a parent commit above them -- you'll see this later in our visualizations.",
              "",
              "In order to clone a repository, you have to unpack or \"resolve\" all these deltas. That's why you might see the command line output:",
              "",
              "`resolving deltas`",
              "",
              "when cloning a repo.",
              "",
              "It's a lot to take in, but for now you can think of commits as snapshots of the project. Commits are very light and switching between them is wicked fast!"
            ]
          }
        },
        {
          "type": "GitDemonstrationView",
          "options": {
            "beforeMarkdowns": [
              "Let's see what this looks like in practice. On the right we have a visualization of a (small) git repository. There are two commits right now -- the first initial commit, `C0`, and one commit after that `C1` that might have some meaningful changes.",
              "",
              "Hit the button below to make a new commit"
            ],
            "afterMarkdowns": [
              "There we go! Awesome. We just made changes to the repository and saved them as a commit. The commit we just made has a parent, `C1`, which references which commit it was based off of."
            ],
            "command": "git commit",
            "beforeCommand": ""
          }
        },
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "Go ahead and try it out on your own! After this window closes, make two commits to complete the level"
            ]
          }
        }
      ]
    },
    "fr_FR": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "## Commits Git",
              "Un commit dans un dépôt (repository) git enregistre une image (snapshot) de tous les fichiers du repertoire. Comme un Copier-Coller g'eant, mais en bien mieux !",
              "",
              "Git fait en sorte que les commits soient aussi légers que possible donc il ne recopie pas tous le répertoire à chaque commit. En fait, git n'enregistre que l'ensemble des changments (\"delta\") depuis la version précédante du dépôt. C'est pour cette raison que la plupart des commits ont un commit parent -- ainsi que nous le verrons plus tard.",
              "",
              "Pour cloner un dépôt, il faut décompresser (\"résoudre\") tous ces deltas. C'est la raison pour laquelle la commande écrit :",
              "",
              "`resolving deltas`",
              "",
              "lorsque l'on clone un dépôt.",
              "",
              "C'est beaucoup à absorber, mais pour l'instant vous pouvez considérer les commits comme des snapshots du projet. Les commits sont tr légers et passer de l'un à l'autre est très rapide !"
            ]
          }
        },
        {
          "type": "GitDemonstrationView",
          "options": {
            "beforeMarkdowns": [
              "Voyons à quoi cela ressemble en pratique. Sur la droite, on peut visualiser un (petit) dépôt git. Il y a pour l'instant deux commits -- le premier commit initial, `C0`, et un commit suivant `C1` qui aurait des changements significatifs.",
              "",
              "Appuyez sur le bouton ci-dessous pour faire un nouveau commit"
            ],
            "afterMarkdowns": [
              "C'est parti ! Super. Nous venons de faire des modifications sur le dépôt et de saugevarder celles-ci dans un commit. Ce commit que nous venons de faire a un parent, `C1`, qui référence le commit sur lequel il est basé."
            ],
            "command": "git commit",
            "beforeCommand": ""
          }
        },
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "Allez-y et essayez par vous-même ! Après la fermeture de cettefenêtre, faites deux commits pour terminer ce niveau."
            ]
          }
        }
      ]
    },
    "ko": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "## Git 커밋",
              "커밋은 Git 저장소에 여러분의 디렉토리에 있는 모든 파일에 대한 스냅샷을 기록하는 것입니다. 디렉토리 전체에 대한 복사해 붙이기와 비슷하지만 훨씬 유용합니다!",
              "",
              "Git은 커밋을 가능한한 가볍게 유지하고자 해서, 커밋할 때마다 디렉토리 전체를 복사하는 일은 하지 않습니다. 각 커밋은 저장소의 이전 버전과 다음 버전의 변경내역(\"delta\"라고도 함)을 저장합니다. 그래서 대부분의 커밋이 그 커밋 위에 부모 커밋을 가리키고 있게 되는 것입니다. -- 곧 그림으로 된 화면에서 살펴보게 될 것입니다.",
              "",
              "저장소를 복제(clone)하려면, 그 모든 변경분(delta)를 풀어내야하는데, 그 때문에 명령행 결과로 아래와 같이 보게됩니다. ",
              "",
              "`resolving deltas`",
              "",
              "알아야할 것이 꽤 많습니다만, 일단은 커밋을 프로젝트의 각각의 스냅샷들로 생각하시는 걸로 충분합니다. 커밋은 매우 가볍고 커밋 사이의 전환도 매우 빠르다는 것을 기억해주세요!"
            ]
          }
        },
        {
          "type": "GitDemonstrationView",
          "options": {
            "beforeMarkdowns": [
              "연습할 때 어떻게 보이는지 확인해보죠. 오른쪽 화면에 git 저장소를 그림으로 표현해 놓았습니다. 현재 두번 커밋한 상태입니다 -- 첫번째 커밋으로 `C0`, 그 다음으로 `C1`이라는 어떤 의미있는 변화가 있는 커밋이 있습니다.",
              "",
              "아래 버튼을 눌러 새로운 커밋을 만들어보세요"
            ],
            "afterMarkdowns": [
              "이렇게 보입니다! 멋지죠. 우리는 방금 저장소 내용을 변경해서 한번의 커밋으로 저장했습니다. 방금 만든 커밋은 부모는 `C1`이고, 어떤 커밋을 기반으로 변경된 것인지를 가리킵니다."
            ],
            "command": "git commit",
            "beforeCommand": ""
          }
        },
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "계속해서 직접 한번 해보세요! 이 창을 닫고, 커밋을 두 번 하면 다음 레벨로 넘어갑니다"
            ]
          }
        }
      ]
    },
    "zh_CN": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "## Git Commits",
              "在一个使用 git 进行版本控制的仓库里，一次提交（commit）给你目录下所有文件做了一次快照，就好像是做了一次复制粘贴，但 git 做的不只那么简单！",
              "",
              "Git 希望尽可能地让这些提交记录保持轻量，所以每次在你进行提交的时候，它不会就这么复制整个工作目录。实际上它把每次提交都记录为一个相对于上个版本变化的集合，或者说一个\"差异 （delta）\"集。这也是为什么绝大部分提交都有一个父对象（parent commit） -- 迟点你就会在我们的演示中看见了。",
              "",
              "假如你要克隆（clone）一个仓库，你就要去解包（unpack）或者“解决（resolve）”这些差异。所以当你克隆一个仓库时会在命令行下看见这样的命令：",
              "",
              "`resolving deltas`",
              "",
              "要完全理解这些概念可能要花费很多时间，但现在你可以把提交看作是项目的快照，提交非常轻量而且在它们之间切换的时候非常快。"
            ]
          }
        },
        {
          "type": "GitDemonstrationView",
          "options": {
            "beforeMarkdowns": [
              "让我们在练习里好好了解提交是什么玩意。在右边展示的是一个使用 git 管理的（小）仓库。现在有两个提交 —— 一个是初始提交 `C0`，另外一个可能包含了一些有意义修改的提交是`C1`。",
              "",
              "点下面的按钮来生成一个新的提交。"
            ],
            "command": "git commit",
            "afterMarkdowns": [
              "看！碉堡吧！我们刚刚对这个仓库进行了一点修改，并且把这些修改提交了。我们刚刚做的提交有一个爸爸（parent），叫 `C1`，代表这个修改是基于`C1`的。"
            ],
            "beforeCommand": ""
          }
        },
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "接下来你可以继续尝试下。在这个窗口关闭之后，提交两遍就可以过关！"
            ]
          }
        }
      ]
    }
  }
};
<commit_msg>fr_FR fixes in intro/1 .<commit_after>exports.level = {
  "name": {
    "en_US": "Introduction to Git Commits",
    "fr_FR": "Introduction aux commits avec Git",
    'ko': 'Git 커밋 소개'
  },
  "goalTreeString": "{\"branches\":{\"master\":{\"target\":\"C3\",\"id\":\"master\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C2\"],\"id\":\"C3\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
  "solutionCommand": "git commit;git commit",
  "startTree": "{\"branches\":{\"master\":{\"target\":\"C1\",\"id\":\"master\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
  "hint": {
    "en_US": "Just type in 'git commit' twice to finish!",
    "fr_FR": "Il suffit de saisir 'git commit' deux fois pour réussir !",
    "zh_CN": "敲两次 'git commit' 就好啦！",
    "ko": "'git commit'이라고 두 번 치세요!"
  },
  "disabledMap": {
    "git revert": true
  },
  "startDialog": {
    "en_US": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "## Git Commits",
              "A commit in a git repository records a snapshot of all the files in your directory. It's like a giant copy and paste, but even better!",
              "",
              "Git wants to keep commits as lightweight as possible though, so it doesn't just copy the entire directory every time you commit. It actually stores each commit as a set of changes, or a \"delta\", from one version of the repository to the next. That's why most commits have a parent commit above them -- you'll see this later in our visualizations.",
              "",
              "In order to clone a repository, you have to unpack or \"resolve\" all these deltas. That's why you might see the command line output:",
              "",
              "`resolving deltas`",
              "",
              "when cloning a repo.",
              "",
              "It's a lot to take in, but for now you can think of commits as snapshots of the project. Commits are very light and switching between them is wicked fast!"
            ]
          }
        },
        {
          "type": "GitDemonstrationView",
          "options": {
            "beforeMarkdowns": [
              "Let's see what this looks like in practice. On the right we have a visualization of a (small) git repository. There are two commits right now -- the first initial commit, `C0`, and one commit after that `C1` that might have some meaningful changes.",
              "",
              "Hit the button below to make a new commit"
            ],
            "afterMarkdowns": [
              "There we go! Awesome. We just made changes to the repository and saved them as a commit. The commit we just made has a parent, `C1`, which references which commit it was based off of."
            ],
            "command": "git commit",
            "beforeCommand": ""
          }
        },
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "Go ahead and try it out on your own! After this window closes, make two commits to complete the level"
            ]
          }
        }
      ]
    },
    "fr_FR": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "## Commits Git",
              "Un commit dans un dépôt (repository) git enregistre une image (snapshot) de tous les fichiers du repertoire. Comme un Copier-Coller géant, mais en bien mieux !",
              "",
              "Git fait en sorte que les commits soient aussi légers que possible donc il ne recopie pas tous le répertoire à chaque commit. En fait, git n'enregistre que l'ensemble des changments (\"delta\") depuis la version précédante du dépôt. C'est pour cette raison que la plupart des commits ont un commit parent -- ainsi que nous le verrons plus tard.",
              "",
              "Pour cloner un dépôt, il faut décompresser (\"résoudre\") tous ces deltas. C'est la raison pour laquelle la commande écrit :",
              "",
              "`resolving deltas`",
              "",
              "lorsque l'on clone un dépôt.",
              "",
              "C'est beaucoup à absorber, mais pour l'instant vous pouvez considérer les commits comme des snapshots du projet. Les commits sont très légers et passer de l'un à l'autre est très rapide !"
            ]
          }
        },
        {
          "type": "GitDemonstrationView",
          "options": {
            "beforeMarkdowns": [
              "Voyons à quoi cela ressemble en pratique. Sur la droite, on peut visualiser un (petit) dépôt git. Il y a pour l'instant deux commits -- le premier commit initial, `C0`, et un commit suivant `C1` qui aurait des changements significatifs.",
              "",
              "Appuyez sur le bouton ci-dessous pour faire un nouveau commit"
            ],
            "afterMarkdowns": [
              "C'est parti ! Super. Nous venons de faire des modifications sur le dépôt et de saugevarder celles-ci dans un commit. Ce commit que nous venons de faire a un parent, `C1`, qui référence le commit sur lequel il est basé."
            ],
            "command": "git commit",
            "beforeCommand": ""
          }
        },
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "Allez-y et essayez par vous-même ! Après la fermeture de cettefenêtre, faites deux commits pour terminer ce niveau."
            ]
          }
        }
      ]
    },
    "ko": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "## Git 커밋",
              "커밋은 Git 저장소에 여러분의 디렉토리에 있는 모든 파일에 대한 스냅샷을 기록하는 것입니다. 디렉토리 전체에 대한 복사해 붙이기와 비슷하지만 훨씬 유용합니다!",
              "",
              "Git은 커밋을 가능한한 가볍게 유지하고자 해서, 커밋할 때마다 디렉토리 전체를 복사하는 일은 하지 않습니다. 각 커밋은 저장소의 이전 버전과 다음 버전의 변경내역(\"delta\"라고도 함)을 저장합니다. 그래서 대부분의 커밋이 그 커밋 위에 부모 커밋을 가리키고 있게 되는 것입니다. -- 곧 그림으로 된 화면에서 살펴보게 될 것입니다.",
              "",
              "저장소를 복제(clone)하려면, 그 모든 변경분(delta)를 풀어내야하는데, 그 때문에 명령행 결과로 아래와 같이 보게됩니다. ",
              "",
              "`resolving deltas`",
              "",
              "알아야할 것이 꽤 많습니다만, 일단은 커밋을 프로젝트의 각각의 스냅샷들로 생각하시는 걸로 충분합니다. 커밋은 매우 가볍고 커밋 사이의 전환도 매우 빠르다는 것을 기억해주세요!"
            ]
          }
        },
        {
          "type": "GitDemonstrationView",
          "options": {
            "beforeMarkdowns": [
              "연습할 때 어떻게 보이는지 확인해보죠. 오른쪽 화면에 git 저장소를 그림으로 표현해 놓았습니다. 현재 두번 커밋한 상태입니다 -- 첫번째 커밋으로 `C0`, 그 다음으로 `C1`이라는 어떤 의미있는 변화가 있는 커밋이 있습니다.",
              "",
              "아래 버튼을 눌러 새로운 커밋을 만들어보세요"
            ],
            "afterMarkdowns": [
              "이렇게 보입니다! 멋지죠. 우리는 방금 저장소 내용을 변경해서 한번의 커밋으로 저장했습니다. 방금 만든 커밋은 부모는 `C1`이고, 어떤 커밋을 기반으로 변경된 것인지를 가리킵니다."
            ],
            "command": "git commit",
            "beforeCommand": ""
          }
        },
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "계속해서 직접 한번 해보세요! 이 창을 닫고, 커밋을 두 번 하면 다음 레벨로 넘어갑니다"
            ]
          }
        }
      ]
    },
    "zh_CN": {
      "childViews": [
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "## Git Commits",
              "在一个使用 git 进行版本控制的仓库里，一次提交（commit）给你目录下所有文件做了一次快照，就好像是做了一次复制粘贴，但 git 做的不只那么简单！",
              "",
              "Git 希望尽可能地让这些提交记录保持轻量，所以每次在你进行提交的时候，它不会就这么复制整个工作目录。实际上它把每次提交都记录为一个相对于上个版本变化的集合，或者说一个\"差异 （delta）\"集。这也是为什么绝大部分提交都有一个父对象（parent commit） -- 迟点你就会在我们的演示中看见了。",
              "",
              "假如你要克隆（clone）一个仓库，你就要去解包（unpack）或者“解决（resolve）”这些差异。所以当你克隆一个仓库时会在命令行下看见这样的命令：",
              "",
              "`resolving deltas`",
              "",
              "要完全理解这些概念可能要花费很多时间，但现在你可以把提交看作是项目的快照，提交非常轻量而且在它们之间切换的时候非常快。"
            ]
          }
        },
        {
          "type": "GitDemonstrationView",
          "options": {
            "beforeMarkdowns": [
              "让我们在练习里好好了解提交是什么玩意。在右边展示的是一个使用 git 管理的（小）仓库。现在有两个提交 —— 一个是初始提交 `C0`，另外一个可能包含了一些有意义修改的提交是`C1`。",
              "",
              "点下面的按钮来生成一个新的提交。"
            ],
            "command": "git commit",
            "afterMarkdowns": [
              "看！碉堡吧！我们刚刚对这个仓库进行了一点修改，并且把这些修改提交了。我们刚刚做的提交有一个爸爸（parent），叫 `C1`，代表这个修改是基于`C1`的。"
            ],
            "beforeCommand": ""
          }
        },
        {
          "type": "ModalAlert",
          "options": {
            "markdowns": [
              "接下来你可以继续尝试下。在这个窗口关闭之后，提交两遍就可以过关！"
            ]
          }
        }
      ]
    }
  }
};
<|endoftext|>


<commit_before>'use strict';
var hbs = require('hbs');
var features = require('./features');
var moment = require('moment');
var path = require('path');
var config = require('./config');

hbs.registerPartials(path.resolve(__dirname + '/../views/partials'));

if (config.env !== 'production') {
  var hbsutils = require('hbs-utils')(hbs);
  hbsutils.registerWatchedPartials(path.resolve(__dirname + '/../views/partials'));
}

hbs.registerHelper('feature', function(request, flag, options) {
  if (features(flag, request)) {
    return options.fn(this);
  } else if (options.inverse) {
    return options.inverse(this);
  }
});

hbs.registerHelper('eachkey', function eachKey(object) {
  var options = arguments[arguments.length - 1];
  var ret = '';
  for (var key in object) {
    if (object.hasOwnProperty(key)) {
      ret += options.fn({
        key: key,
        value: object[key]
      });
    }
  }
  return ret;
});

hbs.registerHelper('encodeURIComponent', function(options) {
  return encodeURIComponent(options.fn(this));
});

hbs.registerHelper('stripeTimestampAsDate', function(timestamp, format, options) {
  return moment(timestamp * 1000).format(format);
});

hbs.registerHelper('divide', function(x, y, dp, options) {
  return (x/y).toFixed(dp) + options.fn(this);
});

hbs.registerHelper('amountPaid', function (invoice) {
  return invoice.total - invoice.amount_due;
});

hbs.registerHelper('percent', function (total, percent, dp) {
  console.log(total, percent);
  return ((total / 100) * (percent / 100)).toFixed(dp);
});

hbs.registerHelper('equal', function(lvalue, rvalue, options) {
  if (arguments.length < 3) {
    return false;
  }
  if (lvalue !== rvalue) {
    return options.inverse(this);
  } else {
    return options.fn(this);
  }
});

hbs.registerHelper('dump', function(obj) {
  return JSON.stringify(obj, null, 2);
});

hbs.registerPartial('welcome_panel', __dirname + '/../views/partials/welcome-panel.html');

module.exports = hbs;<commit_msg>remove console<commit_after>'use strict';
var hbs = require('hbs');
var features = require('./features');
var moment = require('moment');
var path = require('path');
var config = require('./config');

hbs.registerPartials(path.resolve(__dirname + '/../views/partials'));

if (config.env !== 'production') {
  var hbsutils = require('hbs-utils')(hbs);
  hbsutils.registerWatchedPartials(path.resolve(__dirname + '/../views/partials'));
}

hbs.registerHelper('feature', function(request, flag, options) {
  if (features(flag, request)) {
    return options.fn(this);
  } else if (options.inverse) {
    return options.inverse(this);
  }
});

hbs.registerHelper('eachkey', function eachKey(object) {
  var options = arguments[arguments.length - 1];
  var ret = '';
  for (var key in object) {
    if (object.hasOwnProperty(key)) {
      ret += options.fn({
        key: key,
        value: object[key]
      });
    }
  }
  return ret;
});

hbs.registerHelper('encodeURIComponent', function(options) {
  return encodeURIComponent(options.fn(this));
});

hbs.registerHelper('stripeTimestampAsDate', function(timestamp, format, options) {
  return moment(timestamp * 1000).format(format);
});

hbs.registerHelper('divide', function(x, y, dp, options) {
  return (x/y).toFixed(dp) + options.fn(this);
});

hbs.registerHelper('amountPaid', function (invoice) {
  return invoice.total - invoice.amount_due;
});

hbs.registerHelper('percent', function (total, percent, dp) {
  return ((total / 100) * (percent / 100)).toFixed(dp);
});

hbs.registerHelper('equal', function(lvalue, rvalue, options) {
  if (arguments.length < 3) {
    return false;
  }
  if (lvalue !== rvalue) {
    return options.inverse(this);
  } else {
    return options.fn(this);
  }
});

hbs.registerHelper('dump', function(obj) {
  return JSON.stringify(obj, null, 2);
});

hbs.registerPartial('welcome_panel', __dirname + '/../views/partials/welcome-panel.html');

module.exports = hbs;<|endoftext|>


<commit_before>'use strict';

const db = require('./db'),
  file = require('./file');

const META = '-htm',
  HTI = 'hti',
  HTM = 'htm',
  SITE = 'site',
  MENU = 'menu',
  AREA = 'area',
  SECT = 'section';

function mmd(dom, dirs, base) {
  return file.readFile(file.index(dom, [dirs, [base, 'md'].join('.')].join("/")));
}

function data(dom, dirs, base) {
  return new Promise(resolve => {
    db.fetch(dom, dirs, base, HTI)
    .then(dta => resolve(dta))
    .catch(() =>
      db.fetch(dom, dirs, HMD, HTI)
      .then(dtb => resolve(dtb))
      .catch(() =>
        db.fetch(dom, '', HMD, HTI)
        .then(dtc => resolve(dtc))
        .catch(errC => resolve({ error: errC }))
      )
    );
  });
}

function sgmt(dom, dirs, base, xtn) {
  return new Promise(resolve => {
    db.fetch(dom, dirs, base, xtn)
    .then(dta => resolve(dta))
    .catch((e) => resolve({ error: e }));
  });
}

function sgmts(dom, dirs, base) {
  var a = dirs.split('/'),
    area = (a.length>2) ? a.slice(0,a.length-2).join('/') + '/' : '';

  return [
    sgmt(dom,   '', SITE, HTI),
    sgmt(dom,   '', MENU, HTI),
    sgmt(dom, area, AREA, HTI),
    sgmt(dom, dirs, SECT, HTI),
    sgmt(dom, dirs, base, META)

  ];
}
exports.sgmts = sgmts;

function get(dom, dirs, base) {
  return new Promise((resolve, reject) => {
    db.fetch(dom, dirs, base, 'htm')
    .then((cxt) => {
      var ps = sgmts(dom, dirs);
      Promise.all(ps)
      .then(a => {
        cxt.site    = a[0];
        cxt.menu    = a[1];
        cxt.area    = a[2];
        cxt.section = a[3];
        cxt.meta    = a[4];
        cxt.skin = cxt._skin || cxt.meta._skin || cxt.section._skin || cxt.area._skin || cxt.site._skin || HTM;
        if (!cxt.selected && cxt.area.selected) cxt.selected = cxt.area.selected;
        resolve(cxt);
      })
      .catch(e => reject(e));
    })
    .catch(e => {
      if (e.code!=='ENOENT')
        console.log('htm.get Error:', e)
      return reject(e);
    });
  });
}
exports.get = get;
<commit_msg>Use _htm<commit_after>'use strict';

const db = require('./db'),
  file = require('./file');

const META = '-htm',
  HTI = 'hti',
  HTM = '_htm',
  SITE = 'site',
  MENU = 'menu',
  AREA = 'area',
  SECT = 'section';

function mmd(dom, dirs, base) {
  return file.readFile(file.index(dom, [dirs, [base, 'md'].join('.')].join("/")));
}

function data(dom, dirs, base) {
  return new Promise(resolve => {
    db.fetch(dom, dirs, base, HTI)
    .then(dta => resolve(dta))
    .catch(() =>
      db.fetch(dom, dirs, HMD, HTI)
      .then(dtb => resolve(dtb))
      .catch(() =>
        db.fetch(dom, '', HMD, HTI)
        .then(dtc => resolve(dtc))
        .catch(errC => resolve({ error: errC }))
      )
    );
  });
}

function sgmt(dom, dirs, base, xtn) {
  return new Promise(resolve => {
    db.fetch(dom, dirs, base, xtn)
    .then(dta => resolve(dta))
    .catch((e) => resolve({ error: e }));
  });
}

function sgmts(dom, dirs, base) {
  var a = dirs.split('/'),
    area = (a.length>2) ? a.slice(0,a.length-2).join('/') + '/' : '';

  return [
    sgmt(dom,   '', SITE, HTI),
    sgmt(dom,   '', MENU, HTI),
    sgmt(dom, area, AREA, HTI),
    sgmt(dom, dirs, SECT, HTI),
    sgmt(dom, dirs, base, META)

  ];
}
exports.sgmts = sgmts;

function get(dom, dirs, base) {
  return new Promise((resolve, reject) => {
    db.fetch(dom, dirs, base, HTM)
    .then((cxt) => {
      var ps = sgmts(dom, dirs);
      Promise.all(ps)
      .then(a => {
        cxt.site    = a[0];
        cxt.menu    = a[1];
        cxt.area    = a[2];
        cxt.section = a[3];
        cxt.meta    = a[4];
        cxt.skin = cxt._skin || cxt.meta._skin || cxt.section._skin || cxt.area._skin || cxt.site._skin || 'htm';
        if (!cxt.selected && cxt.area.selected) cxt.selected = cxt.area.selected;
        resolve(cxt);
      })
      .catch(e => reject(e));
    })
    .catch(e => {
      if (e.code!=='ENOENT')
        console.log('htm.get Error:', e)
      return reject(e);
    });
  });
}
exports.get = get;
<|endoftext|>


<commit_before>import { setClient } from '../actions';

function checkAuthorization(dispatch) {
  const storedUser = localStorage.getItem('user');

  if (storedUser) {
    const user = JSON.parse(storedUser);
    // const created = Math.round(createdDate.getTime() / 1000);
    // const ttl = 1209600;
    // const expiry = created + ttl;

    // if the user has expired return false
    // if (created > expiry) return false;
    dispatch(setClient(user));
    return true;
  }

  return false;
}

export function checkIndexAuthorization({ dispatch }) {
  return (nextState, replace, next) => {
    if (checkAuthorization(dispatch)) {
      replace('dashboard');
      return next();
    }

    replace('login');
    return next();
  };
}

export function checkDashboardAuthorization({ dispatch, getState }) {
  return (nextState, replace, next) => {
    const user = getState().user;

    if (user) return next();

    if (checkAuthorization(dispatch)) return next();

    replace('login');
    return next();
  };
}

export function checkAdminAuthorization({ dispatch, getState }) {
  return (nextState, replace, next) => {
    if (checkAuthorization(dispatch)) {
      const user = getState().user;
      if (user.id === 1 || user.id === 4) {
        return next();
      }
    }
    replace('forbidden');
    return next();
  };
}
<commit_msg>Add Rasmus as stubbed admin user<commit_after>import { setClient } from '../actions';

function checkAuthorization(dispatch) {
  const storedUser = localStorage.getItem('user');

  if (storedUser) {
    const user = JSON.parse(storedUser);
    // const created = Math.round(createdDate.getTime() / 1000);
    // const ttl = 1209600;
    // const expiry = created + ttl;

    // if the user has expired return false
    // if (created > expiry) return false;
    dispatch(setClient(user));
    return true;
  }

  return false;
}

export function checkIndexAuthorization({ dispatch }) {
  return (nextState, replace, next) => {
    if (checkAuthorization(dispatch)) {
      replace('dashboard');
      return next();
    }

    replace('login');
    return next();
  };
}

export function checkDashboardAuthorization({ dispatch, getState }) {
  return (nextState, replace, next) => {
    const user = getState().user;

    if (user) return next();

    if (checkAuthorization(dispatch)) return next();

    replace('login');
    return next();
  };
}

export function checkAdminAuthorization({ dispatch, getState }) {
  return (nextState, replace, next) => {
    if (checkAuthorization(dispatch)) {
      const user = getState().user;
      if (user.id === 1 || user.email === 'rasmus@designit.com') {
        return next();
      }
    }
    replace('forbidden');
    return next();
  };
}
<|endoftext|>


<commit_before>// Define the namespace
if (typeof Inaka == 'undefined') Inaka = {};
if (typeof Inaka.Jem == 'undefined') Inaka.Jem = {};

// The code
(function()
 {
   // API
   this.encode = function(obj, mtu = 500000)
                 {
                   var dv = new DataView(new ArrayBuffer(mtu));
                   dv.setUint8(0, 131);
                   var [dv, i] = _encodeValue(obj, dv, 1);
                   return dv.buffer.slice(0, i);
                 };
   this.decode = function(buffer)
                 {
                   var dv = new DataView(buffer);
                   if (dv.getUint8(0) != 131)
                     throw "badarg";
                   else
                     return _decodeValue(dv, 1)[0];
                 };

   // Internal functions
   function _encodeValue(value, dv, i)
   {
     if(value === null)
     {
       return _encodeNull(dv, i);
     }
     else
     {
       switch(value.constructor.name)
       {
         case "Object":  return _encodeObject(value, dv, i);
         case "Number":  return _encodeNumber(value, dv, i);
         case "Array":   return _encodeArray(value, dv, i);
         case "String":  return _encodeString(value, dv, i);
         case "Boolean": return _encodeBoolean(value, dv, i);
       }
     }
   }

   function _decodeValue(dv, i)
   {
     switch(dv.getUint8(i))
     {
       case 70:
         return [dv.getFloat64(i + 1), i + 9];
       case 97:
         return [dv.getUint8(i + 1), i + 2];
       case 98:
         return [dv.getInt32(i + 1), i + 5];
       case 100:
         return _decodeAtom(dv, i + 1);
       case 106:
         return [[], i + 1];
       case 108:
         return _decodeArray(dv, i + 1);
       case 109:
         return _decodeString(dv, i + 1);
       case 116:
         return _decodeObject(dv, i + 1);
       default:
         throw "bad_tag: " + dv.getUint8(i);
     }
   }

   function _encodeNull(dv, i)
   {
     dv = _getDataView(dv, i, 6);
     dv.setUint8(i, 100);
     dv.setUint16(i + 1, 3);
     dv.setUint8(i + 3, 110);
     dv.setUint8(i + 4, 105);
     dv.setUint8(i + 5, 108);
     return [dv, i + 6];
   }

   function _decodeAtom(dv, i)
   {
     var l = dv.getUint16(i);
     i += 2;
     var str = "";
     for(var k = 0; k < l; k++)
     {
       str += String.fromCharCode(dv.getUint8(i + k));
     }
     var value;
     switch (str)
     {
       case "nil":  value = null;  break;
       case "true":  value = true;  break;
       case "false": value = false; break;
       default: value = str;
     }
     return [value, i + k];
   }

   function _encodeObject(obj, dv, i)
   {
     dv = _getDataView(dv, i, 5);
     dv.setUint8(i, 116);
     i += 1;
     var keys = Object.keys(obj);
     var l = keys.length
     dv.setUint32(i, l);
     i += 4;
     for(var k = 0; k < l; k++)
     {
       var key = keys[k];
       var [dv, i] = _encodeString(key, dv, i);
       var [dv, i] = _encodeValue(obj[key], dv, i);
     }
     return [dv, i];
   }

   function _decodeObject(dv, i)
   {
     var l = dv.getUint32(i);
     i += 4;
     var obj = {};
     for(var k = 0; k < l; k++)
     {
       // var [key, i] = _decodeString(dv, i + 1);
       var [key, i] = _decodeAtom(dv, i + 1);
       var [value, i] = _decodeValue(dv, i);
       obj[key] = value;
     }
     return [obj, i];
   }

   function _encodeNumber(num, dv, i)
   {
     // Check if we have a float or not
     if (num != Math.floor(num))
     {
       dv = _getDataView(dv, i, 9);
       dv.setUint8(i, 70);
       dv.setFloat64(i + 1, num);
       return [dv, i + 9];
     }
     else
     {
       if (num >= 0 && num < 255)
       {
         dv = _getDataView(dv, i, 2);
         dv.setUint8(i, 97);
         dv.setUint8(i + 1, num);
         return [dv, i + 2];
       }
       else
       {
         dv = _getDataView(dv, i, 5);
         dv.setUint8(i, 98);
         dv.setInt32(i + 1, num);
         return [dv, i + 5];
       }
     }
   }

   function _encodeArray(arr, dv, i)
   {
     dv = _getDataView(dv, i, 5);
     dv.setUint8(i, 108);
     i += 1;
     var l = arr.length;
     dv.setUint32(i, l);
     i += 4;
     for(var k = 0; k < l; k++)
     {
       var [dv, i] = _encodeValue(arr[k], dv, i);
     }
     dv = _getDataView(dv, i, 1);
     dv.setUint8(i, 106);
     return [dv, i + 1];
   }

   function _decodeArray(dv, i)
   {
     var l = dv.getUint32(i);
     i += 4;
     var arr = [];
     for(var k = 0; k < l; k++)
     {
       var [value, i] = _decodeValue(dv, i);
       arr[k] = value;
     }
     return [arr, i + 1];
   }

   function _encodeString(str, dv, i)
   {
     var arr = stringToUint(str);
     var l = arr.length;
     dv = _getDataView(dv, i, l + 5);
     dv.setUint8(i, 109);
     i += 1;
     dv.setUint32(i, l);
     i += 4;
     for(var k = 0; k < l; k++)
     {
       dv.setUint8(i + k, arr[k]);
     }
     return [dv, i + k];
   }

   function _decodeString(dv, i)
   {
     var l = dv.getUint32(i);
     i += 4;
     var arr = [];
     for(var k = 0; k < l; k++)
     {
       arr.push(dv.getUint8(i + k));
     }
     return [uintToString(arr), i + k];
   }

   function stringToUint(string) {
     var string = unescape(encodeURIComponent(string)),
       charList = string.split(''),
       uintArray = [];
     for (var i = 0; i < charList.length; i++) {
       uintArray.push(charList[i].charCodeAt(0));
     }
     return new Uint8Array(uintArray);
   }

   function uintToString(uintArray) {
     var encodedString = String.fromCharCode.apply(null, uintArray),
         decodedString = decodeURIComponent(escape(encodedString));
     return decodedString;
  }

   function _encodeBoolean(bool, dv, i)
   {
     dv = _getDataView(dv, i, 8);
     dv.setUint8(i, 100);
     if (bool)
     {
       dv.setUint16(i + 1, 4);
       dv.setUint32(i + 3, 1953658213);
       return [dv, i + 7];
     }
     else
     {
       dv.setUint16(i + 1, 5);
       dv.setUint8(i + 3, 102);
       dv.setUint32(i + 4, 1634497381);
       return [dv, i + 8];
     }
   }

   // Utils
   function _getDataView(dv, i, l)
   {
     if (dv.byteLength < i + l)
     {
       return new DataView(_expandBuffer(dv.buffer, i + l));
     }
     else
     {
       return dv;
     }
   }

   function _expandBuffer(buffer, minLength)
   {
     var tempArr = new Uint8Array(Math.max(minLength, buffer.length * 2));
     tempArr.set(buffer, 0);
     return tempArr.buffer;
   }
 }).call(Inaka.Jem);
<commit_msg>Decode erlang tuples into javascript arrays [Jem]<commit_after>// Define the namespace
if (typeof Inaka == 'undefined') Inaka = {};
if (typeof Inaka.Jem == 'undefined') Inaka.Jem = {};

// The code
(function()
 {
   // API
   this.encode = function(obj, mtu = 500000)
                 {
                   var dv = new DataView(new ArrayBuffer(mtu));
                   dv.setUint8(0, 131);
                   var [dv, i] = _encodeValue(obj, dv, 1);
                   return dv.buffer.slice(0, i);
                 };
   this.decode = function(buffer)
                 {
                   var dv = new DataView(buffer);
                   if (dv.getUint8(0) != 131)
                     throw "badarg";
                   else
                     return _decodeValue(dv, 1)[0];
                 };

   // Internal functions
   function _encodeValue(value, dv, i)
   {
     if(value === null)
     {
       return _encodeNull(dv, i);
     }
     else
     {
       switch(value.constructor.name)
       {
         case "Object":  return _encodeObject(value, dv, i);
         case "Number":  return _encodeNumber(value, dv, i);
         case "Array":   return _encodeArray(value, dv, i);
         case "String":  return _encodeString(value, dv, i);
         case "Boolean": return _encodeBoolean(value, dv, i);
       }
     }
   }

   function _decodeValue(dv, i)
   {
     switch(dv.getUint8(i))
     {
       case 70:
         return [dv.getFloat64(i + 1), i + 9];
       case 97:
         return [dv.getUint8(i + 1), i + 2];
       case 98:
         return [dv.getInt32(i + 1), i + 5];
       case 100:
         return _decodeAtom(dv, i + 1);
       case 104:
         return _decodeTuple(dv, i + 1);
       case 106:
         return [[], i + 1];
       case 108:
         return _decodeArray(dv, i + 1);
       case 109:
         return _decodeString(dv, i + 1);
       case 116:
         return _decodeObject(dv, i + 1);
       default:
         throw "bad_tag: " + dv.getUint8(i);
     }
   }

   function _encodeNull(dv, i)
   {
     dv = _getDataView(dv, i, 6);
     dv.setUint8(i, 100);
     dv.setUint16(i + 1, 3);
     dv.setUint8(i + 3, 110);
     dv.setUint8(i + 4, 105);
     dv.setUint8(i + 5, 108);
     return [dv, i + 6];
   }

   function _decodeAtom(dv, i)
   {
     var l = dv.getUint16(i);
     i += 2;
     var str = "";
     for(var k = 0; k < l; k++)
     {
       str += String.fromCharCode(dv.getUint8(i + k));
     }
     var value;
     switch (str)
     {
       case "nil":  value = null;  break;
       case "true":  value = true;  break;
       case "false": value = false; break;
       default: value = str;
     }
     return [value, i + k];
   }

   function _encodeObject(obj, dv, i)
   {
     dv = _getDataView(dv, i, 5);
     dv.setUint8(i, 116);
     i += 1;
     var keys = Object.keys(obj);
     var l = keys.length
     dv.setUint32(i, l);
     i += 4;
     for(var k = 0; k < l; k++)
     {
       var key = keys[k];
       var [dv, i] = _encodeString(key, dv, i);
       var [dv, i] = _encodeValue(obj[key], dv, i);
     }
     return [dv, i];
   }

   function _decodeObject(dv, i)
   {
     var l = dv.getUint32(i);
     i += 4;
     var obj = {};
     for(var k = 0; k < l; k++)
     {
       // var [key, i] = _decodeString(dv, i + 1);
       var [key, i] = _decodeAtom(dv, i + 1);
       var [value, i] = _decodeValue(dv, i);
       obj[key] = value;
     }
     return [obj, i];
   }

   function _encodeNumber(num, dv, i)
   {
     // Check if we have a float or not
     if (num != Math.floor(num))
     {
       dv = _getDataView(dv, i, 9);
       dv.setUint8(i, 70);
       dv.setFloat64(i + 1, num);
       return [dv, i + 9];
     }
     else
     {
       if (num >= 0 && num < 255)
       {
         dv = _getDataView(dv, i, 2);
         dv.setUint8(i, 97);
         dv.setUint8(i + 1, num);
         return [dv, i + 2];
       }
       else
       {
         dv = _getDataView(dv, i, 5);
         dv.setUint8(i, 98);
         dv.setInt32(i + 1, num);
         return [dv, i + 5];
       }
     }
   }

   function _encodeArray(arr, dv, i)
   {
     dv = _getDataView(dv, i, 5);
     dv.setUint8(i, 108);
     i += 1;
     var l = arr.length;
     dv.setUint32(i, l);
     i += 4;
     for(var k = 0; k < l; k++)
     {
       var [dv, i] = _encodeValue(arr[k], dv, i);
     }
     dv = _getDataView(dv, i, 1);
     dv.setUint8(i, 106);
     return [dv, i + 1];
   }

   function _decodeTuple(dv, i)
   {
     var l = dv.getUint8(i);
     i += 1;
     var arr = [];
     for(var k = 0; k < l; k++)
     {
       var [value, i] = _decodeValue(dv, i);
       arr[k] = value;
     }
     return [arr, i + 1];
   }

   function _decodeArray(dv, i)
   {
     var l = dv.getUint32(i);
     i += 4;
     var arr = [];
     for(var k = 0; k < l; k++)
     {
       var [value, i] = _decodeValue(dv, i);
       arr[k] = value;
     }
     return [arr, i + 1];
   }

   function _encodeString(str, dv, i)
   {
     var arr = stringToUint(str);
     var l = arr.length;
     dv = _getDataView(dv, i, l + 5);
     dv.setUint8(i, 109);
     i += 1;
     dv.setUint32(i, l);
     i += 4;
     for(var k = 0; k < l; k++)
     {
       dv.setUint8(i + k, arr[k]);
     }
     return [dv, i + k];
   }

   function _decodeString(dv, i)
   {
     var l = dv.getUint32(i);
     i += 4;
     var arr = [];
     for(var k = 0; k < l; k++)
     {
       arr.push(dv.getUint8(i + k));
     }
     return [uintToString(arr), i + k];
   }

   function stringToUint(string) {
     var string = unescape(encodeURIComponent(string)),
       charList = string.split(''),
       uintArray = [];
     for (var i = 0; i < charList.length; i++) {
       uintArray.push(charList[i].charCodeAt(0));
     }
     return new Uint8Array(uintArray);
   }

   function uintToString(uintArray) {
     var encodedString = String.fromCharCode.apply(null, uintArray),
         decodedString = decodeURIComponent(escape(encodedString));
     return decodedString;
  }

   function _encodeBoolean(bool, dv, i)
   {
     dv = _getDataView(dv, i, 8);
     dv.setUint8(i, 100);
     if (bool)
     {
       dv.setUint16(i + 1, 4);
       dv.setUint32(i + 3, 1953658213);
       return [dv, i + 7];
     }
     else
     {
       dv.setUint16(i + 1, 5);
       dv.setUint8(i + 3, 102);
       dv.setUint32(i + 4, 1634497381);
       return [dv, i + 8];
     }
   }

   // Utils
   function _getDataView(dv, i, l)
   {
     if (dv.byteLength < i + l)
     {
       return new DataView(_expandBuffer(dv.buffer, i + l));
     }
     else
     {
       return dv;
     }
   }

   function _expandBuffer(buffer, minLength)
   {
     var tempArr = new Uint8Array(Math.max(minLength, buffer.length * 2));
     tempArr.set(buffer, 0);
     return tempArr.buffer;
   }
 }).call(Inaka.Jem);
<|endoftext|>


<commit_before>(function() {
  Ext.override(Ext.Element, {
    fireEvent: function(eventName, options) {
      if (document.createEvent) {
        // dispatch for firefox + others
        var event = document.createEvent("HTMLEvents");
        event.initEvent(eventName, true, true); // event type,bubbling,cancelable
        event.data = options;
        return this.dom.dispatchEvent(event);
      } else {
        // IE does not support custom events
        // One way to do it : http://dean.edwards.name/weblog/2009/03/callbacks-vs-events/
        // but Element.addListener would have to support it
        throw "Your browser is not W3C compliant."
      }
    },

    callRemote: function() {
      var method = this.getAttribute('method') || this.getAttribute('data-method') || 'GET';
      var url    = this.getAttribute('action') || this.getAttribute('href');

      if (url === undefined) {
        throw "No URL specified for remote call (action or href must be present).";
      } else {
        if (!this.fireEvent("ajax:before")) {
          return (false);
        }
        var options = this.is('form') ? {form: this} : {};
        Ext.Ajax.request(Ext.apply(options, {
          url: url,
          method: method.toUpperCase(),
          scope: this,
          callback: function(options, success, response) {this.fireEvent("ajax:complete", response)},
          success: function(response) {this.fireEvent("ajax:success", response)},
          failure: function(response) {this.fireEvent("ajax:failure", response)}
        }));
        this.fireEvent("ajax:after");
      }
    }
  });

  Ext.rails = {
    sendWithDataMethod: function(element) {
      var templateValues = {method: element.getAttribute('data-method'),
                            href  : element.getAttribute('href')};
      var csrfParam      = Ext.select('meta[name=csrf-param]').item(0);
      var csrfToken      = Ext.select('meta[name=csrf-token]').item(0);
      var formTemplate   = ['<form style="display:none" method="post" action="{href}">',
                            '<input name="_method" value="{method}" type="hidden" />',
                            '</form>'];
      var csrfTemplate   = '<input name="{csrfParam}" value="{csrfToken}" type="hidden" />';

      if (csrfParam != null && csrfToken != null) {
        formTemplate.splice(2, 0, csrfTemplate);
        Ext.apply(templateValues, {csrfParam: csrfParam.getAttribute('content'),
                                   csrfToken: csrfToken.getAttribute('content')});
      }

      var template = new Ext.Template(formTemplate);
      var form = template.append(Ext.getBody(), templateValues);
      form.submit();
    },

    onClick: function(event, element) {
      var element     = Ext.get(element);
      var dataConfirm = element.getAttribute('data-confirm');
      var dataRemote  = element.getAttribute('data-remote');
      var dataMethod  = element.getAttribute('data-method');

      if (!dataConfirm || confirm(dataConfirm)) {
        if (dataRemote) {
          event.preventDefault();
          element.callRemote();
        } else if (dataMethod) {
          event.preventDefault();
          Ext.rails.sendWithDataMethod(element);
        }
      } else {
        event.stopEvent();
      }
    },

    disableWithInput: function(event, element) {
      Ext.fly(element).select('input[data-disable-with]').each(function(input) {
        input.set({'enable-with': input.getValue()}, false);
        input.set({value   : input.getAttribute('data-disable-with'),
                   disabled: 'disabled'});
      });
    },

    enableWithInput: function(event, element) {
      Ext.fly(element).select('input[data-disable-with]').each(function(input) {
        input.set({value: input.getAttribute('enable-with')});
        input.set({disabled: false}, false);
      });
    }
  }

  Ext.getBody().on("click", Ext.rails.onClick, this,
                   {delegate: 'a:any([data-confirm]|[data-remote]|[data-method])'});
  Ext.getBody().on("click", Ext.rails.onClick, this,
                   {delegate: 'input:any([data-confirm]|[data-remote])'});
  Ext.getBody().on("submit", Ext.rails.onClick, this,
                   {delegate: 'form[data-remote]'});
  Ext.getBody().on('ajax:before', Ext.rails.disableWithInput, this,
                   {delegate: 'form[data-remote]:has(input[data-disable-with])'});
  // selector should be form:not([data-remote]):has(input[data-disable-with])
  // but pseudo selectors chaining does not seem to work
  Ext.getBody().on('submit', Ext.rails.disableWithInput, this,
                   {delegate: 'form:has(input[data-disable-with])'});
  Ext.getBody().on('ajax:complete', Ext.rails.enableWithInput, this,
                   {delegate: 'form:has(input[data-disable-with])'});
})();
<commit_msg>throw an error with a more specific message if the browser does not support standard DOM events<commit_after>(function() {
  Ext.override(Ext.Element, {
    fireEvent: function(eventName, options) {
      if (document.createEvent) {
        // dispatch for firefox + others
        var event = document.createEvent("HTMLEvents");
        event.initEvent(eventName, true, true); // event type,bubbling,cancelable
        event.data = options;
        return this.dom.dispatchEvent(event);
      } else {
        // IE does not support custom events
        // One way to do it : http://dean.edwards.name/weblog/2009/03/callbacks-vs-events/
        // but Element.addListener would have to support it
        throw "Your browser does not support standard DOM events."
      }
    },

    callRemote: function() {
      var method = this.getAttribute('method') || this.getAttribute('data-method') || 'GET';
      var url    = this.getAttribute('action') || this.getAttribute('href');

      if (url === undefined) {
        throw "No URL specified for remote call (action or href must be present).";
      } else {
        if (!this.fireEvent("ajax:before")) {
          return (false);
        }
        var options = this.is('form') ? {form: this} : {};
        Ext.Ajax.request(Ext.apply(options, {
          url: url,
          method: method.toUpperCase(),
          scope: this,
          callback: function(options, success, response) {this.fireEvent("ajax:complete", response)},
          success: function(response) {this.fireEvent("ajax:success", response)},
          failure: function(response) {this.fireEvent("ajax:failure", response)}
        }));
        this.fireEvent("ajax:after");
      }
    }
  });

  Ext.rails = {
    sendWithDataMethod: function(element) {
      var templateValues = {method: element.getAttribute('data-method'),
                            href  : element.getAttribute('href')};
      var csrfParam      = Ext.select('meta[name=csrf-param]').item(0);
      var csrfToken      = Ext.select('meta[name=csrf-token]').item(0);
      var formTemplate   = ['<form style="display:none" method="post" action="{href}">',
                            '<input name="_method" value="{method}" type="hidden" />',
                            '</form>'];
      var csrfTemplate   = '<input name="{csrfParam}" value="{csrfToken}" type="hidden" />';

      if (csrfParam != null && csrfToken != null) {
        formTemplate.splice(2, 0, csrfTemplate);
        Ext.apply(templateValues, {csrfParam: csrfParam.getAttribute('content'),
                                   csrfToken: csrfToken.getAttribute('content')});
      }

      var template = new Ext.Template(formTemplate);
      var form = template.append(Ext.getBody(), templateValues);
      form.submit();
    },

    onClick: function(event, element) {
      var element     = Ext.get(element);
      var dataConfirm = element.getAttribute('data-confirm');
      var dataRemote  = element.getAttribute('data-remote');
      var dataMethod  = element.getAttribute('data-method');

      if (!dataConfirm || confirm(dataConfirm)) {
        if (dataRemote) {
          event.preventDefault();
          element.callRemote();
        } else if (dataMethod) {
          event.preventDefault();
          Ext.rails.sendWithDataMethod(element);
        }
      } else {
        event.stopEvent();
      }
    },

    disableWithInput: function(event, element) {
      Ext.fly(element).select('input[data-disable-with]').each(function(input) {
        input.set({'enable-with': input.getValue()}, false);
        input.set({value   : input.getAttribute('data-disable-with'),
                   disabled: 'disabled'});
      });
    },

    enableWithInput: function(event, element) {
      Ext.fly(element).select('input[data-disable-with]').each(function(input) {
        input.set({value: input.getAttribute('enable-with')});
        input.set({disabled: false}, false);
      });
    }
  }

  Ext.getBody().on("click", Ext.rails.onClick, this,
                   {delegate: 'a:any([data-confirm]|[data-remote]|[data-method])'});
  Ext.getBody().on("click", Ext.rails.onClick, this,
                   {delegate: 'input:any([data-confirm]|[data-remote])'});
  Ext.getBody().on("submit", Ext.rails.onClick, this,
                   {delegate: 'form[data-remote]'});
  Ext.getBody().on('ajax:before', Ext.rails.disableWithInput, this,
                   {delegate: 'form[data-remote]:has(input[data-disable-with])'});
  // selector should be form:not([data-remote]):has(input[data-disable-with])
  // but pseudo selectors chaining does not seem to work
  Ext.getBody().on('submit', Ext.rails.disableWithInput, this,
                   {delegate: 'form:has(input[data-disable-with])'});
  Ext.getBody().on('ajax:complete', Ext.rails.enableWithInput, this,
                   {delegate: 'form:has(input[data-disable-with])'});
})();
<|endoftext|>


<commit_before>// Raven.js
//
// Originally based on the Arecibo JavaScript client.
//
// Requires:
//     * TraceKit (included in the full and minified distribution files)

'use strict';

// First, check for JSON support
// If there is no JSON, we no-op the core features of Raven
// since JSON is required to encode the payload
var _Raven = window.Raven,
    hasJSON = !isUndefined(window.JSON),
    globalServer,
    globalUser,
    globalKey,
    globalProject,
    globalOptions = {
        logger: 'javascript',
        ignoreErrors: [],
        ignoreUrls: []
    };

/*
 * The core Raven object
 */
var Raven = {
    VERSION: '@VERSION',

    /*
     * Raven.noConflict()
     *
     * Allow multiple versions of Raven to be installed.
     */
    noConflict: function() {
        window.Raven = _Raven;
        return Raven;
    },

    /*
     * Raven.config()
     *
     * Configure raven with a DSN and extra options
     */
    config: function(dsn, options) {
        var uri = parseUri(dsn),
            lastSlash = uri.path.lastIndexOf('/'),
            path = uri.path.substr(1, lastSlash);

        // merge in options
        if (options) {
            each(options, function(key, value){
                globalOptions[key] = value;
            });
        }

        // "Script error." is hard coded into browsers for errors that it can't read.
        // this is the result of a script being pulled in from an external domain and CORS.
        globalOptions.ignoreErrors.push('Script error.');

        globalKey = uri.user;
        globalProject = ~~uri.path.substr(lastSlash + 1);

        // assemble the endpoint from the uri pieces
        globalServer = uri.protocol + '://' + uri.host +
                      (uri.port ? ':' + uri.port : '') +
                      '/' + path + 'api/' + globalProject + '/store/';

        // return for chaining
        return Raven;
    },

    /*
     * Raven.install()
     *
     * Installs a global window.onerror error handler
     * to capture and report uncaught exceptions.
     */
    install: function() {
        if (!isSetup()) return;

        TraceKit.report.subscribe(handleStackInfo);

        return Raven;
    },

    /*
     * Raven.context()
     *
     * Wrap code within a context so Raven can capture errors
     * reliably across domains that is executed immediately.
     */
    context: function(options, func, args) {
        if (isFunction(options)) {
            args = func;
            func = options;
            options = undefined;
        }

        Raven.wrap(options, func).apply(this, args);
    },

    /* Raven.wrap()
     *
     * Wrap code within a context and returns back a new function to be executed
     */
    wrap: function(options, func) {
        // options is optional
        if (isFunction(options)) {
            func = options;
            options = undefined;
        }

        return function() {
            try {
                func.apply(this, arguments);
            } catch(e) {
                Raven.captureException(e, options);
            }
        };
    },

    /*
     * Raven.uninstall()
     *
     * Uninstalls the global error handler.
     */
    uninstall: function() {
        TraceKit.report.unsubscribe(handleStackInfo);

        return Raven;
    },

    /*
     * Raven.captureException()
     *
     * Manually capture an exception and send it over to Sentry
     */
    captureException: function(ex, options) {
        // TraceKit.report will re-raise any exception passed to it,
        // which means you have to wrap it in try/catch. Instead, we
        // can wrap it here and only re-raise if TraceKit.report
        // raises an exception different from the one we asked to
        // report on.
        try {
            TraceKit.report(ex, options);
        } catch(ex1) {
            if(ex !== ex1) {
                throw ex1;
            }
        }

        return Raven;
    },

    /*
     * Raven.captureMessage()
     *
     * Manually send a message to Sentry
     */
    captureMessage: function(msg, options) {
        // Fire away!
        send(
            arrayMerge({
                message: msg
            }, options)
        );

        return Raven;
    },

    /*
     * Raven.setUser()
     *
     * Set/clear a user to be sent along with the payload.
     */
    setUser: function(user) {
       globalUser = user;

       return Raven;
    }
};

/**** Private functions ****/
function parseUri(str) {
    var keys = 'source protocol authority userInfo user password host port relative path directory file query anchor'.split(' '),
        m = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(str),
        uri = {},
        i = 14;

    while (i--) uri[keys[i]] = m[i] || '';

    return uri;
}

function isUndefined(what) {
    return typeof what === 'undefined';
}

function isFunction(what) {
    return typeof what === 'function';
}

function each(obj, callback) {
    var i, j;

    if (obj.length === undefined) {
        for (i in obj) {
            if (obj.hasOwnProperty(i)) {
                callback.call(null, i, obj[i]);
            }
        }
    } else {
        for (i = 0, j = obj.length; i < j; i++) {
            callback.call(null, i, obj[i]);
        }
    }
}

var cachedAuth;

function getAuthQueryString() {
    if (cachedAuth) return cachedAuth;

    var qs = [
        'sentry_version=2.0',
        'sentry_client=raven-js/' + Raven.VERSION
    ];
    if (globalKey) {
        qs.push('sentry_key=' + globalKey);
    }

    cachedAuth = '?' + qs.join('&');
    return cachedAuth;
}

function handleStackInfo(stackInfo, options) {
    var frames = [], i = stackInfo.stack.length;

    while (i--) frames[i] = normalizeFrame(stackInfo.stack[i]);

    processException(
        stackInfo.name,
        stackInfo.message,
        stackInfo.url,
        stackInfo.lineno,
        frames,
        options
    );
}

function normalizeFrame(frame) {
    // normalize the frames data
    var normalized = {
        abs_path:   frame.url,
        lineno:     frame.line,
        colno:      frame.column,
        'function': frame.func || ''
    }, context = extractContextFromFrame(frame);

    if (context) {
        var i = 3, keys = ['pre_context', 'context_line', 'post_context'];
        while (i--) normalized[keys[i]] = context[i];
    }

    normalized.in_app = !/(Raven|TraceKit)\./.test(normalized['function']);

    return normalized;
}

function extractContextFromFrame(frame) {
    if (!frame.context) return;

    var context = frame.context,
        pivot = ~~(context.length / 2),
        i = context.length, isMinified = false, line;

    while (i--) {
        line = context[i];
        // We're making a guess to see if the source is minified or not.
        // To do that, we make the assumption if *any* of the lines passed
        // in are greater than 300 characters long, we bail.
        // Sentry will see that there isn't a context
        if (line.length > 300) {
            isMinified = true;
            break;
        }
    }

    if (isMinified) {
        // The source is minified and we don't know which column. Fuck it.
        if (isUndefined(frame.column)) return;

        // Source maps are enabled and has a column number, let Sentry try and grab it
        if (globalOptions.sourceMaps) return;

        // If the source is minified with sourcemaps disabled and has a frame column
        // we take a chunk of the offending line to hopefully shed some light
        return [
            [],  // no pre_context
            context[pivot].substr(frame.column, 50), // grab 50 characters, starting at the offending column
            []   // no post_context
        ];
    }

    return [
        context.slice(0, pivot),    // pre_context
        context[pivot],             // context_line
        context.slice(pivot + 1)    // post_context
    ];
}

function processException(type, message, fileurl, lineno, frames, options) {
    var stacktrace, label, i;

    // IE8 really doesn't have Array.prototype.indexOf
    // Filter out a message that matches our ignore list
    i = globalOptions.ignoreErrors.length;
    while (i--) {
        if (message === globalOptions.ignoreErrors[i]) {
            return;
        }
    }

    if (frames && frames.length) {
        stacktrace = {frames: frames};
        fileurl = fileurl || frames[0].filename;
    } else if (fileurl) {
        stacktrace = {
            frames: [{
                filename: fileurl,
                lineno: lineno
            }]
        };
    }

    i = globalOptions.ignoreUrls.length;
    while (i--) {
        if (globalOptions.ignoreUrls[i].test(fileurl)) {
            return;
        }
    }

    label = lineno ? message + ' at ' + lineno : message;

    // Fire away!
    send(
        arrayMerge({
            'sentry.interfaces.Exception': {
                type: type,
                value: message
            },
            'sentry.interfaces.Stacktrace': stacktrace,
            culprit: fileurl,
            message: label
        }, options)
    );
}

function arrayMerge(arr1, arr2) {
    if (!arr2) {
        return arr1;
    }
    each(arr2, function(key, value){
        arr1[key] = value;
    });
    return arr1;
}

function getHttpData() {
    var url = window.location.protocol + '//' + window.location.host + window.location.pathname,
        querystring = window.location.search.slice(1),  // Remove the ?
        http;

    http = {
        url: url,
        querystring: querystring,
        headers: {
            'User-Agent': navigator.userAgent
        }
    };

    if (window.document.referrer) {
        http.headers.Referer = window.document.referrer;
    }

    return http;
}

function send(data) {
    if (!isSetup()) return;

    data = arrayMerge({
        project: globalProject,
        logger: globalOptions.logger,
        site: globalOptions.site,
        platform: 'javascript',
        'sentry.interfaces.Http': getHttpData()
    }, data);

    if (globalUser) data['sentry.interfaces.User'] = globalUser;

    if (isFunction(globalOptions.dataCallback)) {
        data = globalOptions.dataCallback(data);
    }

    makeRequest(data);
}

function makeRequest(data) {
    new Image().src = globalServer + getAuthQueryString() + '&sentry_data=' + encodeURIComponent(JSON.stringify(data));
}

function isSetup() {
    if (!hasJSON) return false;  // needs JSON support
    if (!globalServer) {
        console.error("Error: Raven has not been configured.");
        return false;
    }
    return true;
}
<commit_msg>function shouldn't be an empty string if we can't get it<commit_after>// Raven.js
//
// Originally based on the Arecibo JavaScript client.
//
// Requires:
//     * TraceKit (included in the full and minified distribution files)

'use strict';

// First, check for JSON support
// If there is no JSON, we no-op the core features of Raven
// since JSON is required to encode the payload
var _Raven = window.Raven,
    hasJSON = !isUndefined(window.JSON),
    globalServer,
    globalUser,
    globalKey,
    globalProject,
    globalOptions = {
        logger: 'javascript',
        ignoreErrors: [],
        ignoreUrls: []
    };

/*
 * The core Raven object
 */
var Raven = {
    VERSION: '@VERSION',

    /*
     * Raven.noConflict()
     *
     * Allow multiple versions of Raven to be installed.
     */
    noConflict: function() {
        window.Raven = _Raven;
        return Raven;
    },

    /*
     * Raven.config()
     *
     * Configure raven with a DSN and extra options
     */
    config: function(dsn, options) {
        var uri = parseUri(dsn),
            lastSlash = uri.path.lastIndexOf('/'),
            path = uri.path.substr(1, lastSlash);

        // merge in options
        if (options) {
            each(options, function(key, value){
                globalOptions[key] = value;
            });
        }

        // "Script error." is hard coded into browsers for errors that it can't read.
        // this is the result of a script being pulled in from an external domain and CORS.
        globalOptions.ignoreErrors.push('Script error.');

        globalKey = uri.user;
        globalProject = ~~uri.path.substr(lastSlash + 1);

        // assemble the endpoint from the uri pieces
        globalServer = uri.protocol + '://' + uri.host +
                      (uri.port ? ':' + uri.port : '') +
                      '/' + path + 'api/' + globalProject + '/store/';

        // return for chaining
        return Raven;
    },

    /*
     * Raven.install()
     *
     * Installs a global window.onerror error handler
     * to capture and report uncaught exceptions.
     */
    install: function() {
        if (!isSetup()) return;

        TraceKit.report.subscribe(handleStackInfo);

        return Raven;
    },

    /*
     * Raven.context()
     *
     * Wrap code within a context so Raven can capture errors
     * reliably across domains that is executed immediately.
     */
    context: function(options, func, args) {
        if (isFunction(options)) {
            args = func;
            func = options;
            options = undefined;
        }

        Raven.wrap(options, func).apply(this, args);
    },

    /* Raven.wrap()
     *
     * Wrap code within a context and returns back a new function to be executed
     */
    wrap: function(options, func) {
        // options is optional
        if (isFunction(options)) {
            func = options;
            options = undefined;
        }

        return function() {
            try {
                func.apply(this, arguments);
            } catch(e) {
                Raven.captureException(e, options);
            }
        };
    },

    /*
     * Raven.uninstall()
     *
     * Uninstalls the global error handler.
     */
    uninstall: function() {
        TraceKit.report.unsubscribe(handleStackInfo);

        return Raven;
    },

    /*
     * Raven.captureException()
     *
     * Manually capture an exception and send it over to Sentry
     */
    captureException: function(ex, options) {
        // TraceKit.report will re-raise any exception passed to it,
        // which means you have to wrap it in try/catch. Instead, we
        // can wrap it here and only re-raise if TraceKit.report
        // raises an exception different from the one we asked to
        // report on.
        try {
            TraceKit.report(ex, options);
        } catch(ex1) {
            if(ex !== ex1) {
                throw ex1;
            }
        }

        return Raven;
    },

    /*
     * Raven.captureMessage()
     *
     * Manually send a message to Sentry
     */
    captureMessage: function(msg, options) {
        // Fire away!
        send(
            arrayMerge({
                message: msg
            }, options)
        );

        return Raven;
    },

    /*
     * Raven.setUser()
     *
     * Set/clear a user to be sent along with the payload.
     */
    setUser: function(user) {
       globalUser = user;

       return Raven;
    }
};

/**** Private functions ****/
function parseUri(str) {
    var keys = 'source protocol authority userInfo user password host port relative path directory file query anchor'.split(' '),
        m = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(str),
        uri = {},
        i = 14;

    while (i--) uri[keys[i]] = m[i] || '';

    return uri;
}

function isUndefined(what) {
    return typeof what === 'undefined';
}

function isFunction(what) {
    return typeof what === 'function';
}

function each(obj, callback) {
    var i, j;

    if (obj.length === undefined) {
        for (i in obj) {
            if (obj.hasOwnProperty(i)) {
                callback.call(null, i, obj[i]);
            }
        }
    } else {
        for (i = 0, j = obj.length; i < j; i++) {
            callback.call(null, i, obj[i]);
        }
    }
}

var cachedAuth;

function getAuthQueryString() {
    if (cachedAuth) return cachedAuth;

    var qs = [
        'sentry_version=2.0',
        'sentry_client=raven-js/' + Raven.VERSION
    ];
    if (globalKey) {
        qs.push('sentry_key=' + globalKey);
    }

    cachedAuth = '?' + qs.join('&');
    return cachedAuth;
}

function handleStackInfo(stackInfo, options) {
    var frames = [], i = stackInfo.stack.length;

    while (i--) frames[i] = normalizeFrame(stackInfo.stack[i]);

    processException(
        stackInfo.name,
        stackInfo.message,
        stackInfo.url,
        stackInfo.lineno,
        frames,
        options
    );
}

function normalizeFrame(frame) {
    // normalize the frames data
    var normalized = {
        abs_path:   frame.url,
        lineno:     frame.line,
        colno:      frame.column,
        'function': frame.func || '?'
    }, context = extractContextFromFrame(frame);

    if (context) {
        var i = 3, keys = ['pre_context', 'context_line', 'post_context'];
        while (i--) normalized[keys[i]] = context[i];
    }

    normalized.in_app = !/(Raven|TraceKit)\./.test(normalized['function']);

    return normalized;
}

function extractContextFromFrame(frame) {
    if (!frame.context) return;

    var context = frame.context,
        pivot = ~~(context.length / 2),
        i = context.length, isMinified = false, line;

    while (i--) {
        line = context[i];
        // We're making a guess to see if the source is minified or not.
        // To do that, we make the assumption if *any* of the lines passed
        // in are greater than 300 characters long, we bail.
        // Sentry will see that there isn't a context
        if (line.length > 300) {
            isMinified = true;
            break;
        }
    }

    if (isMinified) {
        // The source is minified and we don't know which column. Fuck it.
        if (isUndefined(frame.column)) return;

        // Source maps are enabled and has a column number, let Sentry try and grab it
        if (globalOptions.sourceMaps) return;

        // If the source is minified with sourcemaps disabled and has a frame column
        // we take a chunk of the offending line to hopefully shed some light
        return [
            [],  // no pre_context
            context[pivot].substr(frame.column, 50), // grab 50 characters, starting at the offending column
            []   // no post_context
        ];
    }

    return [
        context.slice(0, pivot),    // pre_context
        context[pivot],             // context_line
        context.slice(pivot + 1)    // post_context
    ];
}

function processException(type, message, fileurl, lineno, frames, options) {
    var stacktrace, label, i;

    // IE8 really doesn't have Array.prototype.indexOf
    // Filter out a message that matches our ignore list
    i = globalOptions.ignoreErrors.length;
    while (i--) {
        if (message === globalOptions.ignoreErrors[i]) {
            return;
        }
    }

    if (frames && frames.length) {
        stacktrace = {frames: frames};
        fileurl = fileurl || frames[0].filename;
    } else if (fileurl) {
        stacktrace = {
            frames: [{
                filename: fileurl,
                lineno: lineno
            }]
        };
    }

    i = globalOptions.ignoreUrls.length;
    while (i--) {
        if (globalOptions.ignoreUrls[i].test(fileurl)) {
            return;
        }
    }

    label = lineno ? message + ' at ' + lineno : message;

    // Fire away!
    send(
        arrayMerge({
            'sentry.interfaces.Exception': {
                type: type,
                value: message
            },
            'sentry.interfaces.Stacktrace': stacktrace,
            culprit: fileurl,
            message: label
        }, options)
    );
}

function arrayMerge(arr1, arr2) {
    if (!arr2) {
        return arr1;
    }
    each(arr2, function(key, value){
        arr1[key] = value;
    });
    return arr1;
}

function getHttpData() {
    var url = window.location.protocol + '//' + window.location.host + window.location.pathname,
        querystring = window.location.search.slice(1),  // Remove the ?
        http;

    http = {
        url: url,
        querystring: querystring,
        headers: {
            'User-Agent': navigator.userAgent
        }
    };

    if (window.document.referrer) {
        http.headers.Referer = window.document.referrer;
    }

    return http;
}

function send(data) {
    if (!isSetup()) return;

    data = arrayMerge({
        project: globalProject,
        logger: globalOptions.logger,
        site: globalOptions.site,
        platform: 'javascript',
        'sentry.interfaces.Http': getHttpData()
    }, data);

    if (globalUser) data['sentry.interfaces.User'] = globalUser;

    if (isFunction(globalOptions.dataCallback)) {
        data = globalOptions.dataCallback(data);
    }

    makeRequest(data);
}

function makeRequest(data) {
    new Image().src = globalServer + getAuthQueryString() + '&sentry_data=' + encodeURIComponent(JSON.stringify(data));
}

function isSetup() {
    if (!hasJSON) return false;  // needs JSON support
    if (!globalServer) {
        console.error("Error: Raven has not been configured.");
        return false;
    }
    return true;
}
<|endoftext|>


<commit_before>import Factory from './jsonapi-factory';
import { hubURL } from '@cardstack/hub/environment';

export default class Fixtures {
  constructor(fn) {
    this.factory = new Factory();
    this._id = null;
    fn(this.factory);
  }
  async setup() {
    if (this._id == null) {
      await this._restoreCheckpoint('empty');
      for (let model of inDependencyOrder(this.factory.getModels())) {
        let response = await fetch(`${hubURL}/api/${model.type}`, {
          method: 'POST',
          body: JSON.stringify({
            data: {
              id: model.id,
              type: model.type,
              attributes: model.attributes,
              relationships: model.relationships
            }
          })
        });
        if (response.status !== 201) {
          throw new Error(`Unexpected response ${response.status} while trying to define fixtures: ${await response.text()}`);
        }
      }
      this._id = await this._createCheckpoint();
    } else {
      await this._restoreCheckpoint(this._id);
    }
  }

  async _createCheckpoint() {
    let response = await fetch(`${hubURL}/api/ephemeral-checkpoints`, {
      method: 'POST',
      body: JSON.stringify({
        data: { type: 'ephemeral-checkpoints' }
      })
    });
    if (response.status !== 201) {
      throw new Error(`Unexpected response ${response.status} while trying to create checkpoint: ${await response.text()}`);
    }
    return (await response.json()).data.id;
  }

  async _restoreCheckpoint(id) {
    let response = await fetch(`${hubURL}/api/ephemeral-restores`, {
      method: 'POST',
      body: JSON.stringify({
        data: {
          type: 'ephemeral-restores',
          relationships: {
            checkpoint: {
              data: { type: 'ephemeral-checkpoints', id }
            }
          }
        }
      })
    });
    if (response.status !== 201) {
      throw new Error(`Unexpected response ${response.status} while trying to restore cehckpoint: ${await response.text()}`);
    }
  }
}

// FIXME: this requires more understanding of the schema than is
// appropriate in this module. Also, this is duplicated in
// test-support/env
function inDependencyOrder(models) {
  let priority = ['default-values', 'plugin-configs', 'constraints', 'fields', 'data-sources', 'content-types'];
  return priority.map(type => models.filter(m => m.type === type)).reduce((a,b) => a.concat(b), []).concat(models.filter(m => !priority.includes(m.type)));
}
<commit_msg>ensure realtime-ness of the ephemeral test fixtures on first run<commit_after>import Factory from './jsonapi-factory';
import { hubURL } from '@cardstack/hub/environment';

export default class Fixtures {
  constructor(fn) {
    this.factory = new Factory();
    this._id = null;
    fn(this.factory);
  }
  async setup() {
    if (this._id == null) {
      await this._restoreCheckpoint('empty');
      for (let model of inDependencyOrder(this.factory.getModels())) {
        let response = await fetch(`${hubURL}/api/${model.type}`, {
          method: 'POST',
          body: JSON.stringify({
            data: {
              id: model.id,
              type: model.type,
              attributes: model.attributes,
              relationships: model.relationships
            }
          })
        });
        if (response.status !== 201) {
          throw new Error(`Unexpected response ${response.status} while trying to define fixtures: ${await response.text()}`);
        }
      }
      this._id = await this._createCheckpoint();
    }
    // this restores even on the first pass because it's a way to block until indexing happens
    await this._restoreCheckpoint(this._id);
  }

  async _createCheckpoint() {
    let response = await fetch(`${hubURL}/api/ephemeral-checkpoints`, {
      method: 'POST',
      body: JSON.stringify({
        data: { type: 'ephemeral-checkpoints' }
      })
    });
    if (response.status !== 201) {
      throw new Error(`Unexpected response ${response.status} while trying to create checkpoint: ${await response.text()}`);
    }
    return (await response.json()).data.id;
  }

  async _restoreCheckpoint(id) {
    let response = await fetch(`${hubURL}/api/ephemeral-restores`, {
      method: 'POST',
      body: JSON.stringify({
        data: {
          type: 'ephemeral-restores',
          relationships: {
            checkpoint: {
              data: { type: 'ephemeral-checkpoints', id }
            }
          }
        }
      })
    });
    if (response.status !== 201) {
      throw new Error(`Unexpected response ${response.status} while trying to restore cehckpoint: ${await response.text()}`);
    }
  }
}

// FIXME: this requires more understanding of the schema than is
// appropriate in this module. Also, this is duplicated in
// test-support/env
function inDependencyOrder(models) {
  let priority = ['default-values', 'plugin-configs', 'constraints', 'fields', 'data-sources', 'content-types'];
  return priority.map(type => models.filter(m => m.type === type)).reduce((a,b) => a.concat(b), []).concat(models.filter(m => !priority.includes(m.type)));
}
<|endoftext|>


<commit_before>var inflector;
module('ember-inflector.dsl', {
  setup: function() {
    inflector = new Ember.Inflector(/* no rulest == no rules */);
  },
  teardown: function() {
    inflector = undefined;
  }
});

test('ability to add additonal pluralization rules', function(){
  equal(inflector.pluralize('cow'), 'cow', 'no pluralization rule');

  inflector.plural(/$/, 's');

  equal(inflector.pluralize('cow'), 'cows', 'pluralization rule was applied');
});

test('ability to add additonal singularization rules', function(){
  equal(inflector.singularize('cows'), 'cows', 'no singularization rule was applied');

  inflector.singular(/s$/, '');

  equal(inflector.singularize('cows'), 'cow', 'singularization rule was applied');
});

test('ability to add additonal uncountable rules', function(){
  inflector.plural(/$/, 's');
  equal(inflector.pluralize('cow'), 'cows', 'pluralization rule was applied');

  inflector.uncountable('cow');
  equal(inflector.pluralize('cow'), 'cow', 'pluralization rule NOT was applied');
});

test('ability to add additonal irregular rules', function(){
  inflector.singular(/s$/, '');
  inflector.plural(/$/, 's');

  equal(inflector.singularize('cows'), 'cow', 'regular singularization rule was applied');
  equal(inflector.pluralize('cow'), 'cows', 'regular pluralization rule was applied');

  inflector.irregular('cow', 'kine');

  equal(inflector.singularize('kine'), 'cow', 'irregular singularization rule was applied');
  equal(inflector.pluralize('cow'), 'kine', 'irregular pluralization rule was applied');
});

module('ember-inflector.unit');

test('plurals', function() {
  expect(1);

  var inflector = new Ember.Inflector({
    plurals: [
      [/$/, 's'],
      [/s$/i, 's']
    ]
  });

  equal(inflector.pluralize('apple'), 'apples');
});

test('singularization',function(){
  expect(1);

  var inflector = new Ember.Inflector({
    singular: [
      [/s$/i, ''],
      [/(ss)$/i, '$1']
    ]
  });

  equal(inflector.singularize('apple'), 'apple');
});

test('plural',function(){
  expect(1);

  var inflector = new Ember.Inflector({
    plurals: [
      ['1', '1'],
      ['2', '2'],
      ['3', '3']
    ]
  });

  equal(inflector.rules.plurals.length, 3);
});

test('singular',function(){
  expect(1);

  var inflector = new Ember.Inflector({
    singular: [
      ['1', '1'],
      ['2', '2'],
      ['3', '3']
    ]
  });

  equal(inflector.rules.singular.length, 3);
});

test('irregular',function(){
  expect(6);

  var inflector = new Ember.Inflector({
    irregularPairs: [
      ['1', '12'],
      ['2', '22'],
      ['3', '32']
    ]
  });

  equal(inflector.rules.irregular['1'], '12');
  equal(inflector.rules.irregular['2'], '22');
  equal(inflector.rules.irregular['3'], '32');

  equal(inflector.rules.irregularInverse['12'], '1');
  equal(inflector.rules.irregularInverse['22'], '2');
  equal(inflector.rules.irregularInverse['32'], '3');
});

test('uncountable',function(){
  expect(3);

  var inflector = new Ember.Inflector({
    uncountable: [
      '1',
      '2',
      '3'
    ]
  });

  equal(inflector.rules.uncountable['1'], true);
  equal(inflector.rules.uncountable['2'], true);
  equal(inflector.rules.uncountable['3'], true);
});

test('inflect.nothing', function(){
  expect(2);

  var inflector = new Ember.Inflector();

  equal(inflector.inflect('',  []), '');
  equal(inflector.inflect(' ', []), ' ');
});

test('inflect.noRules',function(){
  expect(1);

  var inflector = new Ember.Inflector();

  equal(inflector.inflect('word', []),'word');
});

test('inflect.uncountable', function(){
  expect(1);

  var inflector = new Ember.Inflector({
    plural: [
      [/$/,'s']
    ],
    uncountable: [
      'word'
    ]
  });

  var rules = [];

  equal(inflector.inflect('word', rules), 'word');
});

test('inflect.irregular', function(){
  expect(2);

  var inflector = new Ember.Inflector({
    irregularPairs: [
      ['word', 'wordy']
    ]
  });

  var rules = [];

  equal(inflector.inflect('word', rules), 'wordy');
  equal(inflector.inflect('wordy', rules), 'word');
});

test('inflect.basicRules', function(){
  expect(1);

  var inflector = new Ember.Inflector();
  var rules = [[/$/, 's']];

  equal(inflector.inflect('word', rules ), 'words');
});

test('inflect.advancedRules', function(){
  expect(1);

  var inflector = new Ember.Inflector();
  var rules = [[/^(ox)$/i, '$1en']];

  equal(inflector.inflect('ox', rules), 'oxen');
});
<commit_msg>Test for singularization of irregulars<commit_after>var inflector;
module('ember-inflector.dsl', {
  setup: function() {
    inflector = new Ember.Inflector(/* no rulest == no rules */);
  },
  teardown: function() {
    inflector = undefined;
  }
});

test('ability to add additonal pluralization rules', function(){
  equal(inflector.pluralize('cow'), 'cow', 'no pluralization rule');

  inflector.plural(/$/, 's');

  equal(inflector.pluralize('cow'), 'cows', 'pluralization rule was applied');
});

test('ability to add additonal singularization rules', function(){
  equal(inflector.singularize('cows'), 'cows', 'no singularization rule was applied');

  inflector.singular(/s$/, '');

  equal(inflector.singularize('cows'), 'cow', 'singularization rule was applied');
});

test('ability to add additonal uncountable rules', function(){
  inflector.plural(/$/, 's');
  equal(inflector.pluralize('cow'), 'cows', 'pluralization rule was applied');

  inflector.uncountable('cow');
  equal(inflector.pluralize('cow'), 'cow', 'pluralization rule NOT was applied');
});

test('ability to add additonal irregular rules', function(){
  inflector.singular(/s$/, '');
  inflector.plural(/$/, 's');

  equal(inflector.singularize('cows'), 'cow', 'regular singularization rule was applied');
  equal(inflector.pluralize('cow'), 'cows', 'regular pluralization rule was applied');

  inflector.irregular('cow', 'kine');

  equal(inflector.singularize('kine'), 'cow', 'irregular singularization rule was applied');
  equal(inflector.pluralize('cow'), 'kine', 'irregular pluralization rule was applied');
});

module('ember-inflector.unit');

test('plurals', function() {
  expect(1);

  var inflector = new Ember.Inflector({
    plurals: [
      [/$/, 's'],
      [/s$/i, 's']
    ]
  });

  equal(inflector.pluralize('apple'), 'apples');
});

test('singularization',function(){
  expect(1);

  var inflector = new Ember.Inflector({
    singular: [
      [/s$/i, ''],
      [/(ss)$/i, '$1']
    ]
  });

  equal(inflector.singularize('apple'), 'apple');
});

test('singularization of irregulars', function(){
  expect(1);

  var inflector = new Ember.Inflector({
    irregularPairs: [
      ['person', 'people']
    ]
  });

  equal(inflector.singularize('person'), 'person');
});

test('plural',function(){
  expect(1);

  var inflector = new Ember.Inflector({
    plurals: [
      ['1', '1'],
      ['2', '2'],
      ['3', '3']
    ]
  });

  equal(inflector.rules.plurals.length, 3);
});

test('singular',function(){
  expect(1);

  var inflector = new Ember.Inflector({
    singular: [
      ['1', '1'],
      ['2', '2'],
      ['3', '3']
    ]
  });

  equal(inflector.rules.singular.length, 3);
});

test('irregular',function(){
  expect(6);

  var inflector = new Ember.Inflector({
    irregularPairs: [
      ['1', '12'],
      ['2', '22'],
      ['3', '32']
    ]
  });

  equal(inflector.rules.irregular['1'], '12');
  equal(inflector.rules.irregular['2'], '22');
  equal(inflector.rules.irregular['3'], '32');

  equal(inflector.rules.irregularInverse['12'], '1');
  equal(inflector.rules.irregularInverse['22'], '2');
  equal(inflector.rules.irregularInverse['32'], '3');
});

test('uncountable',function(){
  expect(3);

  var inflector = new Ember.Inflector({
    uncountable: [
      '1',
      '2',
      '3'
    ]
  });

  equal(inflector.rules.uncountable['1'], true);
  equal(inflector.rules.uncountable['2'], true);
  equal(inflector.rules.uncountable['3'], true);
});

test('inflect.nothing', function(){
  expect(2);

  var inflector = new Ember.Inflector();

  equal(inflector.inflect('',  []), '');
  equal(inflector.inflect(' ', []), ' ');
});

test('inflect.noRules',function(){
  expect(1);

  var inflector = new Ember.Inflector();

  equal(inflector.inflect('word', []),'word');
});

test('inflect.uncountable', function(){
  expect(1);

  var inflector = new Ember.Inflector({
    plural: [
      [/$/,'s']
    ],
    uncountable: [
      'word'
    ]
  });

  var rules = [];

  equal(inflector.inflect('word', rules), 'word');
});

test('inflect.irregular', function(){
  expect(2);

  var inflector = new Ember.Inflector({
    irregularPairs: [
      ['word', 'wordy']
    ]
  });

  var rules = [];

  equal(inflector.inflect('word', rules), 'wordy');
  equal(inflector.inflect('wordy', rules), 'word');
});

test('inflect.basicRules', function(){
  expect(1);

  var inflector = new Ember.Inflector();
  var rules = [[/$/, 's']];

  equal(inflector.inflect('word', rules ), 'words');
});

test('inflect.advancedRules', function(){
  expect(1);

  var inflector = new Ember.Inflector();
  var rules = [[/^(ox)$/i, '$1en']];

  equal(inflector.inflect('ox', rules), 'oxen');
});
<|endoftext|>


<commit_before>exports.default = function (opts) {
  return {
    configure: function (configuration) {
      console.log('stub configured', configuration)
    },
    load: function () {
      console.log('stub loaded')
    },
    unload: function () {
      console.log('stub unloaded')
    }
  }
}

exports.configurationSchema = {
  type: 'object',
  properties: {
    foo: {
      type: 'string'
    }
  },
  required: ['foo']
}
<commit_msg>chore(package): lots of comments<commit_after>// This is one of the simplest xo-server's plugin than can be created.

// This (optional) schema is used to describe the expected
// configuration of the plugin.
//
// It will be used to generate a configuration UI (xo-web) and to
// validate the provided configuration.
exports.configurationSchema = {
  type: 'object',
  properties: {
    foo: {
      type: 'string'
    }
  },
  required: ['foo']
}

// The default export is just a factory function which will create an
// instance of the plugin.
// Usually it will be called only once, at startup.
//
// Its only parameter is an object which currently only contains a
// `xo` property: the instance of the currently running xo-server.
exports.default = function (opts) {

  // For simplicity's sake, this plugin returns a plain object, but
  // usually it returns a new instance of an existing class.
  return {

    // This (optional) method is called each time the plugin is
    // (re-)configured.
    //
    // Note: before being called, the configuration is validated
    // against the provided configuration schema.
    configure: function (configuration) {
      console.log('stub configured', configuration)
    },

    // This method is called to load the plugin.
    //
    // Note 1: will only be called if the plugin is currently
    // unloaded.
    //
    // Note 2: if the plugin is configurable, will only be called if
    // the plugin has been successfully configured.
    load: function () {
      console.log('stub loaded')
    },

    // This (optional) method is called to unload the plugin.
    //
    // Note: will only be called if the plugin is currently loaded.
    unload: function () {
      console.log('stub unloaded')
    }
  }
}
<|endoftext|>