<commit_before>import Home from './pages/home.vue';
import About from './pages/about.vue';

import Accordion from './pages/accordion.vue';
import ActionSheet from './pages/action-sheet.vue';
import Autocomplete from './pages/autocomplete.vue';
import Badge from './pages/badge.vue';
import Buttons from './pages/buttons.vue';
import Cards from './pages/cards.vue';
import Checkbox from './pages/checkbox.vue';
import Chips from './pages/chips.vue';
import ContactsList from './pages/contacts-list.vue';
import ContentBlock from './pages/content-block.vue';
import DataTable from './pages/data-table.vue';
import Dialog from './pages/dialog.vue';
import Fab from './pages/fab.vue';
import FabMorph from './pages/fab-morph.vue';
import FormStorage from './pages/form-storage.vue';
import Grid from './pages/grid.vue';
import Icons from './pages/icons.vue';
import InfiniteScroll from './pages/infinite-scroll.vue';
import Inputs from './pages/inputs.vue';
import LazyLoad from './pages/lazy-load.vue';
import List from './pages/list.vue';
import LoginScreen from './pages/login-screen.vue';
import LoginScreenPage from './pages/login-screen-page.vue';
import Messages from './pages/messages.vue';
import Navbar from './pages/navbar.vue';
import NavbarHideScroll from './pages/navbar-hide-scroll.vue';
import Notifications from './pages/notifications.vue';
import Panel from './pages/panel.vue';
import PhotoBrowser from './pages/photo-browser.vue';
import Popup from './pages/popup.vue';
import Popover from './pages/popover.vue';
import Preloader from './pages/preloader.vue';
import Progressbar from './pages/progressbar.vue';
import PullToRefresh from './pages/pull-to-refresh.vue';
import Radio from './pages/radio.vue';
import Range from './pages/range.vue';
import Searchbar from './pages/searchbar.vue';
import SearchbarExpandable from './pages/searchbar-expandable.vue';
import SheetModal from './pages/sheet-modal.vue';
import SmartSelect from './pages/smart-select.vue';
import Sortable from './pages/sortable.vue';
import Statusbar from './pages/statusbar.vue';
import Subnavbar from './pages/subnavbar.vue';
import SubnavbarTitle from './pages/subnavbar-title.vue';
import Swiper from './pages/swiper.vue';
import SwiperHorizontal from './pages/swiper-horizontal.vue';
import SwiperVertical from './pages/swiper-vertical.vue';
import SwiperSpaceBetween from './pages/swiper-space-between.vue';
import SwiperMultiple from './pages/swiper-multiple.vue';
import SwiperNested from './pages/swiper-nested.vue';
import SwiperLoop from './pages/swiper-loop.vue';
import Swiper3dCube from './pages/swiper-3d-cube.vue';
import Swiper3dCoverflow from './pages/swiper-3d-coverflow.vue';
import Swiper3dFlip from './pages/swiper-3d-flip.vue';
import SwiperFade from './pages/swiper-fade.vue';
import SwiperScrollbar from './pages/swiper-scrollbar.vue';
import SwiperGallery from './pages/swiper-gallery.vue';
import SwiperCustomControls from './pages/swiper-custom-controls.vue';
import SwiperParallax from './pages/swiper-parallax.vue';
import SwiperLazy from './pages/swiper-lazy.vue';
import SwiperPaginationProgress from './pages/swiper-pagination-progress.vue';
import SwiperPaginationFraction from './pages/swiper-pagination-fraction.vue';
import SwiperZoom from './pages/swiper-zoom.vue';
import Swipeout from './pages/swipeout.vue';
import Tabs from './pages/tabs.vue';
import TabsStatic from './pages/tabs-static.vue';
import TabsAnimated from './pages/tabs-animated.vue';
import TabsSwipeable from './pages/tabs-swipeable.vue';
import TabsRoutable from './pages/tabs-routable.vue';
import Toast from './pages/toast.vue';
import Toggle from './pages/toggle.vue';
import ToolbarTabbar from './pages/toolbar-tabbar.vue';
import Tabbar from './pages/tabbar.vue';
import TabbarLabels from './pages/tabbar-labels.vue';
import TabbarScrollable from './pages/tabbar-scrollable.vue';
import ToolbarHideScroll from './pages/toolbar-hide-scroll.vue';
import Timeline from './pages/timeline.vue';
import TimelineVertical from './pages/timeline-vertical.vue';
import TimelineHorizontal from './pages/timeline-horizontal.vue';
import TimelineHorizontalCalendar from './pages/timeline-horizontal-calendar.vue';
import VirtualList from './pages/virtual-list.vue';
import ColorThemes from './pages/color-themes.vue';

// Pages
export default [
  // Index page
  {
    path: '/',
    component: Home,
  },
  // About page
  {
    path: '/about/',
    component: About,
  },
  // Right Panel pages
  {
    path: '/panel-right-1/',
    content: '\

\

\

\

\
              \
                \
                Back\
              \

\

Panel Page 1
\

\

\

\

\

This is a right panel page 1
\

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quo saepe aspernatur inventore dolorum voluptates consequatur tempore ipsum! Quia, incidunt, aliquam sit veritatis nisi aliquid porro similique ipsa mollitia eaque ex!
\

\

\

\
    ',
  },
  {
    path: '/panel-right-2/',
    content: '\

\

\

\

\
              \
                \
                Back\
              \

\

Panel Page 2
\

\

\

\

\

This is a right panel page 2
\

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quo saepe aspernatur inventore dolorum voluptates consequatur tempore ipsum! Quia, incidunt, aliquam sit veritatis nisi aliquid porro similique ipsa mollitia eaque ex!
\

\

\

\
    ',
  },

  // Components
  {
    path: '/accordion/',
    component: Accordion,
  },
  {
    path: '/action-sheet/',
    component: ActionSheet,
  },
  {
    path: '/autocomplete/',
    component: Autocomplete,
  },
  {
    path: '/badge/',
    component: Badge,
  },
  {
    path: '/buttons/',
    component: Buttons,
  },
  {
    path: '/cards/',
    component: Cards,
  },
  {
    path: '/checkbox/',
    component: Checkbox,
  },
  {
    path: '/chips/',
    component: Chips,
  },
  {
    path: '/contacts-list/',
    component: ContactsList,
  },
  {
    path: '/content-block/',
    component: ContentBlock,
  },
  {
    path: '/data-table/',
    component: DataTable,
  },
  {
    path: '/dialog/',
    component: Dialog,
  },
  {
    path: '/fab/',
    component: Fab,
  },
  {
    path: '/fab-morph/',
    component: FabMorph,
  },
  {
    path: '/form-storage/',
    component: FormStorage,
  },
  {
    path: '/grid/',
    component: Grid,
  },
  {
    path: '/icons/',
    component: Icons,
  },
  {
    path: '/infinite-scroll/',
    component: InfiniteScroll,
  },
  {
    path: '/inputs/',
    component: Inputs,
  },
  {
    path: '/lazy-load/',
    component: LazyLoad,
  },
  {
    path: '/list/',
    component: List,
  },
  {
    path: '/login-screen/',
    component: LoginScreen,
  },
  {
    path: '/login-screen-page/',
    component: LoginScreenPage,
  },
  {
    path: '/messages/',
    component: Messages,
  },
  {
    path: '/navbar/',
    component: Navbar,
  },
  {
    path: '/navbar-hide-scroll/',
    component: NavbarHideScroll,
  },
  {
    path: '/notifications/',
    component: Notifications,
  },
  {
    path: '/panel/',
    component: Panel,
  },
  {
    path: '/photo-browser/',
    component: PhotoBrowser,
  },
  {
    path: '/popup/',
    component: Popup,
  },
  {
    path: '/popover/',
    component: Popover,
  },
  {
    path: '/preloader/',
    component: Preloader,
  },
  {
    path: '/progressbar/',
    component: Progressbar,
  },
  {
    path: '/pull-to-refresh/',
    component: PullToRefresh,
  },
  {
    path: '/radio/',
    component: Radio,
  },
  {
    path: '/range/',
    component: Range,
  },
  {
    path: '/searchbar/',
    component: Searchbar,
  },
  {
    path: '/searchbar-expandable/',
    component: SearchbarExpandable,
  },
  {
    path: '/sheet-modal/',
    component: SheetModal,
  },
  {
    path: '/smart-select/',
    component: SmartSelect,
  },
  {
    path: '/sortable/',
    component: Sortable,
  },
  {
    path: '/statusbar/',
    component: Statusbar,
  },
  {
    path: '/subnavbar/',
    component: Subnavbar,
  },
  {
    path: '/subnavbar-title/',
    component: SubnavbarTitle,
  },
  {
    path: '/swiper/',
    component: Swiper,
    routes: [
      {
        path: 'swiper-horizontal/',
        component: SwiperHorizontal,
      },
      {
        path: 'swiper-vertical/',
        component: SwiperVertical,
      },
      {
        path: 'swiper-space-between/',
        component: SwiperSpaceBetween,
      },
      {
        path: 'swiper-multiple/',
        component: SwiperMultiple,
      },
      {
        path: 'swiper-nested/',
        component: SwiperNested,
      },
      {
        path: 'swiper-loop/',
        component: SwiperLoop,
      },
      {
        path: 'swiper-3d-cube/',
        component: Swiper3dCube,
      },
      {
        path: 'swiper-3d-coverflow/',
        component: Swiper3dCoverflow,
      },
      {
        path: 'swiper-3d-flip/',
        component: Swiper3dFlip,
      },
      {
        path: 'swiper-fade/',
        component: SwiperFade,
      },
      {
        path: 'swiper-scrollbar/',
        component: SwiperScrollbar,
      },
      {
        path: 'swiper-gallery/',
        component: SwiperGallery,
      },
      {
        path: 'swiper-custom-controls/',
        component: SwiperCustomControls,
      },
      {
        path: 'swiper-parallax/',
        component: SwiperParallax,
      },
      {
        path: 'swiper-lazy/',
        component: SwiperLazy,
      },
      {
        path: 'swiper-pagination-progress/',
        component: SwiperPaginationProgress,
      },
      {
        path: 'swiper-pagination-fraction/',
        component: SwiperPaginationFraction,
      },
      {
        path: 'swiper-zoom/',
        component: SwiperZoom,
      },
    ],
  },
  {
    path: '/swipeout/',
    component: Swipeout,
  },
  {
    path: '/tabs/',
    component: Tabs,
  },
  {
    path: '/tabs-static/',
    component: TabsStatic,
  },
  {
    path: '/tabs-animated/',
    component: TabsAnimated,
  },
  {
    path: '/tabs-swipeable/',
    component: TabsSwipeable,
  },
  {
    path: '/tabs-routable/',
    component: TabsRoutable,
    tabs: [
      {
        path: '/',
        id: 'tab1',
        content: ' \

 \

Tab 1 content
 \

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ullam enim quia molestiae facilis laudantium voluptates obcaecati officia cum, sit libero commodi. Ratione illo suscipit temporibus sequi iure ad laboriosam accusamus?
 \

Saepe explicabo voluptas ducimus provident, doloremque quo totam molestias! Suscipit blanditiis eaque exercitationem praesentium reprehenderit, fuga accusamus possimus sed, sint facilis ratione quod, qui dignissimos voluptas! Aliquam rerum consequuntur deleniti.
 \

Totam reprehenderit amet commodi ipsum nam provident doloremque possimus odio itaque, est animi culpa modi consequatur reiciendis corporis libero laudantium sed eveniet unde delectus a maiores nihil dolores? Natus, perferendis.
 \

 \
        ',
      },
      {
        path: '/tab2/',
        id: 'tab2',
        content: '\

 \

Tab 2 content
 \

Suscipit, facere quasi atque totam. Repudiandae facilis at optio atque, rem nam, natus ratione cum enim voluptatem suscipit veniam! Repellat, est debitis. Modi nam mollitia explicabo, unde aliquid impedit! Adipisci!
 \

Deserunt adipisci tempora asperiores, quo, nisi ex delectus vitae consectetur iste fugiat iusto dolorem autem. Itaque, ipsa voluptas, a assumenda rem, dolorum porro accusantium, officiis veniam nostrum cum cumque impedit.
 \

Laborum illum ipsa voluptatibus possimus nesciunt ex consequatur rem, natus ad praesentium rerum libero consectetur temporibus cupiditate atque aspernatur, eaque provident eligendi quaerat ea soluta doloremque. Iure fugit, minima facere.
 \

 \
        ',
      },
      {
        path: '/tab3/',
        id: 'tab3',
        content: '\

 \

Tab 3 content
 \

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ullam enim quia molestiae facilis laudantium voluptates obcaecati officia cum, sit libero commodi. Ratione illo suscipit temporibus sequi iure ad laboriosam accusamus?
 \

Deserunt adipisci tempora asperiores, quo, nisi ex delectus vitae consectetur iste fugiat iusto dolorem autem. Itaque, ipsa voluptas, a assumenda rem, dolorum porro accusantium, officiis veniam nostrum cum cumque impedit.
 \

Laborum illum ipsa voluptatibus possimus nesciunt ex consequatur rem, natus ad praesentium rerum libero consectetur temporibus cupiditate atque aspernatur, eaque provident eligendi quaerat ea soluta doloremque. Iure fugit, minima facere.
 \

 \
        ',
      },
    ],
  },
  {
    path: '/toast/',
    component: Toast,
  },
  {
    path: '/toggle/',
    component: Toggle,
  },
  {
    path: '/toolbar-tabbar/',
    component: ToolbarTabbar,
    routes: [
      {
        path: 'tabbar/',
        component: Tabbar,
      },
      {
        path: 'tabbar-labels/',
        component: TabbarLabels,
      },
      {
        path: 'tabbar-scrollable/',
        component: TabbarScrollable,
      },
      {
        path: 'toolbar-hide-scroll/',
        component: ToolbarHideScroll,
      },
    ],
  },
  {
    path: '/timeline/',
    component: Timeline,
  },
  {
    path: '/timeline-vertical/',
    component: TimelineVertical,
  },
  {
    path: '/timeline-horizontal/',
    component: TimelineHorizontal,
  },
  {
    path: '/timeline-horizontal-calendar/',
    component: TimelineHorizontalCalendar,
  },
  {
    path: '/virtual-list/',
    component: VirtualList,
  },

  // Color Themes
  {
    path: '/color-themes/',
    component: ColorThemes,
  },

];
<commit_msg>Fix lint errors<commit_after>import Home from './pages/home.vue';
import About from './pages/about.vue';

import Accordion from './pages/accordion.vue';
import ActionSheet from './pages/action-sheet.vue';
import Autocomplete from './pages/autocomplete.vue';
import Badge from './pages/badge.vue';
import Buttons from './pages/buttons.vue';
import Cards from './pages/cards.vue';
import Checkbox from './pages/checkbox.vue';
import Chips from './pages/chips.vue';
import ContactsList from './pages/contacts-list.vue';
import ContentBlock from './pages/content-block.vue';
import DataTable from './pages/data-table.vue';
import Dialog from './pages/dialog.vue';
import Fab from './pages/fab.vue';
import FabMorph from './pages/fab-morph.vue';
import FormStorage from './pages/form-storage.vue';
import Grid from './pages/grid.vue';
import Icons from './pages/icons.vue';
import InfiniteScroll from './pages/infinite-scroll.vue';
import Inputs from './pages/inputs.vue';
import LazyLoad from './pages/lazy-load.vue';
import List from './pages/list.vue';
import LoginScreen from './pages/login-screen.vue';
import LoginScreenPage from './pages/login-screen-page.vue';
import Messages from './pages/messages.vue';
import Navbar from './pages/navbar.vue';
import NavbarHideScroll from './pages/navbar-hide-scroll.vue';
import Notifications from './pages/notifications.vue';
import Panel from './pages/panel.vue';
import PhotoBrowser from './pages/photo-browser.vue';
import Popup from './pages/popup.vue';
import Popover from './pages/popover.vue';
import Preloader from './pages/preloader.vue';
import Progressbar from './pages/progressbar.vue';
import PullToRefresh from './pages/pull-to-refresh.vue';
import Radio from './pages/radio.vue';
import Range from './pages/range.vue';
import Searchbar from './pages/searchbar.vue';
import SearchbarExpandable from './pages/searchbar-expandable.vue';
import SheetModal from './pages/sheet-modal.vue';
import SmartSelect from './pages/smart-select.vue';
import Sortable from './pages/sortable.vue';
import Statusbar from './pages/statusbar.vue';
import Subnavbar from './pages/subnavbar.vue';
import SubnavbarTitle from './pages/subnavbar-title.vue';
import Swiper from './pages/swiper.vue';
import SwiperHorizontal from './pages/swiper-horizontal.vue';
import SwiperVertical from './pages/swiper-vertical.vue';
import SwiperSpaceBetween from './pages/swiper-space-between.vue';
import SwiperMultiple from './pages/swiper-multiple.vue';
import SwiperNested from './pages/swiper-nested.vue';
import SwiperLoop from './pages/swiper-loop.vue';
import Swiper3dCube from './pages/swiper-3d-cube.vue';
import Swiper3dCoverflow from './pages/swiper-3d-coverflow.vue';
import Swiper3dFlip from './pages/swiper-3d-flip.vue';
import SwiperFade from './pages/swiper-fade.vue';
import SwiperScrollbar from './pages/swiper-scrollbar.vue';
import SwiperGallery from './pages/swiper-gallery.vue';
import SwiperCustomControls from './pages/swiper-custom-controls.vue';
import SwiperParallax from './pages/swiper-parallax.vue';
import SwiperLazy from './pages/swiper-lazy.vue';
import SwiperPaginationProgress from './pages/swiper-pagination-progress.vue';
import SwiperPaginationFraction from './pages/swiper-pagination-fraction.vue';
import SwiperZoom from './pages/swiper-zoom.vue';
import Swipeout from './pages/swipeout.vue';
import Tabs from './pages/tabs.vue';
import TabsStatic from './pages/tabs-static.vue';
import TabsAnimated from './pages/tabs-animated.vue';
import TabsSwipeable from './pages/tabs-swipeable.vue';
import TabsRoutable from './pages/tabs-routable.vue';
import Toast from './pages/toast.vue';
import Toggle from './pages/toggle.vue';
import ToolbarTabbar from './pages/toolbar-tabbar.vue';
import Tabbar from './pages/tabbar.vue';
import TabbarLabels from './pages/tabbar-labels.vue';
import TabbarScrollable from './pages/tabbar-scrollable.vue';
import ToolbarHideScroll from './pages/toolbar-hide-scroll.vue';
import Timeline from './pages/timeline.vue';
import TimelineVertical from './pages/timeline-vertical.vue';
import TimelineHorizontal from './pages/timeline-horizontal.vue';
import TimelineHorizontalCalendar from './pages/timeline-horizontal-calendar.vue';
import VirtualList from './pages/virtual-list.vue';
import ColorThemes from './pages/color-themes.vue';

// Pages
export default [
  // Index page
  {
    path: '/',
    component: Home,
  },
  // About page
  {
    path: '/about/',
    component: About,
  },
  // Right Panel pages
  {
    path: '/panel-right-1/',
    content: `

                Back

Panel Page 1

This is a right panel page 1

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quo saepe aspernatur inventore dolorum voluptates consequatur tempore ipsum! Quia, incidunt, aliquam sit veritatis nisi aliquid porro similique ipsa mollitia eaque ex!

    `,
  },
  {
    path: '/panel-right-2/',
    content: `

                Back

Panel Page 2

This is a right panel page 2

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quo saepe aspernatur inventore dolorum voluptates consequatur tempore ipsum! Quia, incidunt, aliquam sit veritatis nisi aliquid porro similique ipsa mollitia eaque ex!

    `,
  },

  // Components
  {
    path: '/accordion/',
    component: Accordion,
  },
  {
    path: '/action-sheet/',
    component: ActionSheet,
  },
  {
    path: '/autocomplete/',
    component: Autocomplete,
  },
  {
    path: '/badge/',
    component: Badge,
  },
  {
    path: '/buttons/',
    component: Buttons,
  },
  {
    path: '/cards/',
    component: Cards,
  },
  {
    path: '/checkbox/',
    component: Checkbox,
  },
  {
    path: '/chips/',
    component: Chips,
  },
  {
    path: '/contacts-list/',
    component: ContactsList,
  },
  {
    path: '/content-block/',
    component: ContentBlock,
  },
  {
    path: '/data-table/',
    component: DataTable,
  },
  {
    path: '/dialog/',
    component: Dialog,
  },
  {
    path: '/fab/',
    component: Fab,
  },
  {
    path: '/fab-morph/',
    component: FabMorph,
  },
  {
    path: '/form-storage/',
    component: FormStorage,
  },
  {
    path: '/grid/',
    component: Grid,
  },
  {
    path: '/icons/',
    component: Icons,
  },
  {
    path: '/infinite-scroll/',
    component: InfiniteScroll,
  },
  {
    path: '/inputs/',
    component: Inputs,
  },
  {
    path: '/lazy-load/',
    component: LazyLoad,
  },
  {
    path: '/list/',
    component: List,
  },
  {
    path: '/login-screen/',
    component: LoginScreen,
  },
  {
    path: '/login-screen-page/',
    component: LoginScreenPage,
  },
  {
    path: '/messages/',
    component: Messages,
  },
  {
    path: '/navbar/',
    component: Navbar,
  },
  {
    path: '/navbar-hide-scroll/',
    component: NavbarHideScroll,
  },
  {
    path: '/notifications/',
    component: Notifications,
  },
  {
    path: '/panel/',
    component: Panel,
  },
  {
    path: '/photo-browser/',
    component: PhotoBrowser,
  },
  {
    path: '/popup/',
    component: Popup,
  },
  {
    path: '/popover/',
    component: Popover,
  },
  {
    path: '/preloader/',
    component: Preloader,
  },
  {
    path: '/progressbar/',
    component: Progressbar,
  },
  {
    path: '/pull-to-refresh/',
    component: PullToRefresh,
  },
  {
    path: '/radio/',
    component: Radio,
  },
  {
    path: '/range/',
    component: Range,
  },
  {
    path: '/searchbar/',
    component: Searchbar,
  },
  {
    path: '/searchbar-expandable/',
    component: SearchbarExpandable,
  },
  {
    path: '/sheet-modal/',
    component: SheetModal,
  },
  {
    path: '/smart-select/',
    component: SmartSelect,
  },
  {
    path: '/sortable/',
    component: Sortable,
  },
  {
    path: '/statusbar/',
    component: Statusbar,
  },
  {
    path: '/subnavbar/',
    component: Subnavbar,
  },
  {
    path: '/subnavbar-title/',
    component: SubnavbarTitle,
  },
  {
    path: '/swiper/',
    component: Swiper,
    routes: [
      {
        path: 'swiper-horizontal/',
        component: SwiperHorizontal,
      },
      {
        path: 'swiper-vertical/',
        component: SwiperVertical,
      },
      {
        path: 'swiper-space-between/',
        component: SwiperSpaceBetween,
      },
      {
        path: 'swiper-multiple/',
        component: SwiperMultiple,
      },
      {
        path: 'swiper-nested/',
        component: SwiperNested,
      },
      {
        path: 'swiper-loop/',
        component: SwiperLoop,
      },
      {
        path: 'swiper-3d-cube/',
        component: Swiper3dCube,
      },
      {
        path: 'swiper-3d-coverflow/',
        component: Swiper3dCoverflow,
      },
      {
        path: 'swiper-3d-flip/',
        component: Swiper3dFlip,
      },
      {
        path: 'swiper-fade/',
        component: SwiperFade,
      },
      {
        path: 'swiper-scrollbar/',
        component: SwiperScrollbar,
      },
      {
        path: 'swiper-gallery/',
        component: SwiperGallery,
      },
      {
        path: 'swiper-custom-controls/',
        component: SwiperCustomControls,
      },
      {
        path: 'swiper-parallax/',
        component: SwiperParallax,
      },
      {
        path: 'swiper-lazy/',
        component: SwiperLazy,
      },
      {
        path: 'swiper-pagination-progress/',
        component: SwiperPaginationProgress,
      },
      {
        path: 'swiper-pagination-fraction/',
        component: SwiperPaginationFraction,
      },
      {
        path: 'swiper-zoom/',
        component: SwiperZoom,
      },
    ],
  },
  {
    path: '/swipeout/',
    component: Swipeout,
  },
  {
    path: '/tabs/',
    component: Tabs,
  },
  {
    path: '/tabs-static/',
    component: TabsStatic,
  },
  {
    path: '/tabs-animated/',
    component: TabsAnimated,
  },
  {
    path: '/tabs-swipeable/',
    component: TabsSwipeable,
  },
  {
    path: '/tabs-routable/',
    component: TabsRoutable,
    tabs: [
      {
        path: '/',
        id: 'tab1',
        content: `

Tab 1 content

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ullam enim quia molestiae facilis laudantium voluptates obcaecati officia cum, sit libero commodi. Ratione illo suscipit temporibus sequi iure ad laboriosam accusamus?

Saepe explicabo voluptas ducimus provident, doloremque quo totam molestias! Suscipit blanditiis eaque exercitationem praesentium reprehenderit, fuga accusamus possimus sed, sint facilis ratione quod, qui dignissimos voluptas! Aliquam rerum consequuntur deleniti.

Totam reprehenderit amet commodi ipsum nam provident doloremque possimus odio itaque, est animi culpa modi consequatur reiciendis corporis libero laudantium sed eveniet unde delectus a maiores nihil dolores? Natus, perferendis.

        `,
      },
      {
        path: '/tab2/',
        id: 'tab2',
        content: `

Tab 2 content

Suscipit, facere quasi atque totam. Repudiandae facilis at optio atque, rem nam, natus ratione cum enim voluptatem suscipit veniam! Repellat, est debitis. Modi nam mollitia explicabo, unde aliquid impedit! Adipisci!

Deserunt adipisci tempora asperiores, quo, nisi ex delectus vitae consectetur iste fugiat iusto dolorem autem. Itaque, ipsa voluptas, a assumenda rem, dolorum porro accusantium, officiis veniam nostrum cum cumque impedit.

Laborum illum ipsa voluptatibus possimus nesciunt ex consequatur rem, natus ad praesentium rerum libero consectetur temporibus cupiditate atque aspernatur, eaque provident eligendi quaerat ea soluta doloremque. Iure fugit, minima facere.

        `,
      },
      {
        path: '/tab3/',
        id: 'tab3',
        content: `

Tab 3 content

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ullam enim quia molestiae facilis laudantium voluptates obcaecati officia cum, sit libero commodi. Ratione illo suscipit temporibus sequi iure ad laboriosam accusamus?

Deserunt adipisci tempora asperiores, quo, nisi ex delectus vitae consectetur iste fugiat iusto dolorem autem. Itaque, ipsa voluptas, a assumenda rem, dolorum porro accusantium, officiis veniam nostrum cum cumque impedit.

Laborum illum ipsa voluptatibus possimus nesciunt ex consequatur rem, natus ad praesentium rerum libero consectetur temporibus cupiditate atque aspernatur, eaque provident eligendi quaerat ea soluta doloremque. Iure fugit, minima facere.

        `,
      },
    ],
  },
  {
    path: '/toast/',
    component: Toast,
  },
  {
    path: '/toggle/',
    component: Toggle,
  },
  {
    path: '/toolbar-tabbar/',
    component: ToolbarTabbar,
    routes: [
      {
        path: 'tabbar/',
        component: Tabbar,
      },
      {
        path: 'tabbar-labels/',
        component: TabbarLabels,
      },
      {
        path: 'tabbar-scrollable/',
        component: TabbarScrollable,
      },
      {
        path: 'toolbar-hide-scroll/',
        component: ToolbarHideScroll,
      },
    ],
  },
  {
    path: '/timeline/',
    component: Timeline,
  },
  {
    path: '/timeline-vertical/',
    component: TimelineVertical,
  },
  {
    path: '/timeline-horizontal/',
    component: TimelineHorizontal,
  },
  {
    path: '/timeline-horizontal-calendar/',
    component: TimelineHorizontalCalendar,
  },
  {
    path: '/virtual-list/',
    component: VirtualList,
  },

  // Color Themes
  {
    path: '/color-themes/',
    component: ColorThemes,
  },

];
<|endoftext|>


<commit_before><commit_msg>feat(RSAPublicKey): initial class definition<commit_after>'use strict'

/**
 * Dependencies
 */
const JWK = require('./JWK')

/**
 * RSAPublicKey
 */
class RSAPublicKey extends JWK {}

/**
 * Export
 */
module.exports = RSAPublicKey
<|endoftext|>


<commit_before>(function(root, factory) {
	if (typeof define === 'function' && define.amd) {
		// AMD. Register as an anonymous module.
		define(["knockout", "jquery"], factory);
	} else {
		// Browser globals
		factory(ko, $);
	}
}(this, function(ko, $) {
	ko.bindingHandlers.magicTextarea = {
		init: function(element) {
			var $element = $(element);

			$element.on('keydown keyup input paste propertychange click submit mouseenter', function(){
				element.style.height = "auto";
				$element.height(element.scrollHeight - element.clientHeight);
			});
		}
	};
}));<commit_msg>Add min height<commit_after>(function(root, factory) {
	if (typeof define === 'function' && define.amd) {
		// AMD. Register as an anonymous module.
		define(["knockout", "jquery"], factory);
	} else {
		// Browser globals
		factory(ko, $);
	}
}(this, function(ko, $) {
	ko.bindingHandlers.magicTextarea = {
		init: function(element) {
			var $element = $(element);

			$element.on('keydown keyup input paste propertychange click submit mouseenter', function(){
				element.style.height = "auto";
				$element.height(16 + (element.scrollHeight - element.clientHeight));
			});
		}
	};
}));<|endoftext|>


<commit_before>'use strict';

const defaultTo = require('lodash/defaultTo');
const throttle = require('lodash/throttle');
const LRU = require('lru-cache');
const Tile = require('../core/Tile');
const EventType = require('../event/EventType');
const TileEvent = require('../event/TileEvent');

// Constants

/**
 * Number of the tiles held in the pyramid.
 * @private
 * @constant {Number}
 */
const CACHE_SIZE = 128;

/**
 * Number of persistant zoom levels held in the pyramids.
 * @private
 * @constant {Number}
 */
const PERSISTANT_LEVELS = 4;

/**
 * Loaded event throttle in milliseconds.
 * @private
 * @constant {Number}
 */
const LOADED_THROTTLE_MS = 200;

// Private Methods

const getLODOffset = function(descendant, ancestor) {
	const scale = Math.pow(2, descendant.z - ancestor.z);
	const step = 1 / scale;
	const root = {
		x: ancestor.x * scale,
		y: ancestor.y * scale
	};
	return {
		x: (descendant.x - root.x) * step,
		y: (descendant.y - root.y) * step,
		extent: step
	};
};

const add = function(pyramid, tile) {
	if (tile.coord.z < pyramid.persistantLevels) {
		// persistant tiles
		if (pyramid.persistants.has(tile.coord.hash)) {
			throw `Tile of coord ${tile.coord.hash} already exists in the pyramid`;
		}
		pyramid.persistants.set(tile.coord.hash, tile);
	} else {
		// non-persistant tiles
		if (pyramid.tiles.has(tile.coord.hash)) {
			throw `Tile of coord ${tile.coord.hash} already exists in the pyramid`;
		}
		pyramid.tiles.set(tile.coord.hash, tile);
	}
	// store in level arrays
	if (!pyramid.levels.has(tile.coord.z)) {
		pyramid.levels.set(tile.coord.z, []);
	}
	pyramid.levels.get(tile.coord.z).push(tile);
	// emit add
	pyramid.layer.emit(EventType.TILE_ADD, new TileEvent(pyramid.layer, tile));
};

const remove = function(pyramid, tile) {
	if (tile.coord.z < pyramid.persistantLevels) {
		throw `Tile of coord ${tile.coord.hash} is flagged as persistant and cannot be removed`;
	}
	if (!pyramid.tiles.has(tile.coord.hash)) {
		throw `Tile of coord ${tile.coord.hash} does not exists in the pyramid`;
	}
	// remove from levels
	const level = pyramid.levels.get(tile.coord.z);
	level.splice(level.indexOf(tile), 1);
	if (level.length === 0) {
		pyramid.levels.delete(tile.coord.z);
	}
	// emit remove
	pyramid.layer.emit(EventType.TILE_REMOVE, new TileEvent(pyramid.layer, tile));
};

const sumPowerOfFour = function(n) {
	return (1/3) * (Math.pow(4, n) - 1);
};

const checkIfLoaded = throttle(function(pyramid) {
	// if no more pending tiles, emit load
	if (pyramid.pending.size === 0) {
		pyramid.layer.emit(EventType.LOAD, new TileEvent(pyramid.layer, null));
	}
}, LOADED_THROTTLE_MS);

/**
 * Class representing a pyramid of tiles.
 */
class TilePyramid {

	/**
	 * Instantiates a new Bounds object.
	 *
	 * @param {Layer} layer - The layer object.
	 * @param {Object} options - The pyramid options.
	 * @param {Number} options.cacheSize - The size of the tile cache.
	 * @param {Number} options.persistantLevels - The number of persistant levels in the pyramid.
	 */
	constructor(layer, options = {}) {
		if (!layer) {
			throw 'No layer parameter provided';
		}
		this.cacheSize = defaultTo(options.cacheSize, CACHE_SIZE);
		this.persistantLevels = defaultTo(options.persistantLevels, PERSISTANT_LEVELS);
		this.totalCapacity = this.cacheSize + sumPowerOfFour(this.persistantLevels);
		this.layer = layer;
		this.levels = new Map();
		this.persistants = new Map();
		this.pending = new Map();
		this.tiles = new LRU({
			max: this.cacheSize,
			dispose: (key, tile) => {
				remove(this, tile);
			}
		});
	}

	/**
	 * Test whether or not a coord is held in cache in the pyramid.
	 *
	 * @param {Coord} coord - The coord to test.
	 *
	 * @returns {boolean} Whether or not the coord exists in the pyramid.
	 */
	has(coord) {
		if (coord.z < this.persistantLevels) {
			return this.persistants.has(coord.hash);
		}
		return this.tiles.has(coord.hash);
	}

	/**
	 * Test whether or not a coord is currently pending.
	 *
	 * @param {Coord} coord - The coord to test.
	 *
	 * @returns {boolean} Whether or not the coord is currently pending.
	 */
	isPending(coord) {
		return this.pending.has(coord.hash);
	}

	/**
	 * Returns the tile matching the provided coord. If the tile does not
	 * exist, returns undefined.
	 *
	 * @param {Coord} coord - The coord of the tile to return.
	 *
	 * @returns {Tile} The tile object.
	 */
	get(coord) {
		if (coord.z < this.persistantLevels) {
			return this.persistants.get(coord.hash);
		}
		return this.tiles.get(coord.hash);
	}

	/**
	 * Returns the closest ancestor of the provided coord. If no ancestor
	 * exists in the pyramid, returns undefined.
	 *
	 * @param {Coord} coord - The coord of the tile.
	 *
	 * @return {Coord} The closest available ancestor of the provided coord.
	 */
	getClosestAncestor(coord) {
		// get ancestors levels, in descending order
		const levels = [...this.levels.keys()]
			.sort((a, b) => {
				// sort by key
				return b - a;
			}).filter(entry => {
				// filter by key
				return (entry < coord.z);
			});
		// check for closest ancestor
		for (let i=0; i<levels.length; i++) {
			const level = levels[i];
			const ancestor = coord.getAncestor(coord.z - level);
			if (this.has(ancestor)) {
				return ancestor;
			}
		}
		return undefined;
	}

	/**
	 * Returns true if the coordinate is no in the current or target
	 * viewport.
	 *
	 * @param {Plot} plot - The plot object.
	 * @param {Coord} coord - The coord to test.
	 *
	 * @returns {boolean} Whether or not the tile is stale.
	 */
	isStale(plot, coord) {
		// if zooming, use target zoom, if not use current zoom
		const animation = plot.zoomAnimation;
		const viewport = animation ? animation.targetViewport : plot.viewport;
		const zoom = animation ? animation.targetZoom : plot.zoom;
		return !viewport.isInView(plot.tileSize, coord, zoom);
	}

	/**
	 * Requests tiles for the provided coords. If the tiles already exist
	 * in the pyramid or is currently pending no request is made.
	 *
	 * @param {Plot} plot - The plot object.
	 * @param {Array} coords - The array of coords to request.
	 */
	requestTiles(plot, coords) {
		// request tiles
		coords.forEach(coord => {
			// get normalized coord, we use normalized coords for requests
			// so that we do not track / request the same tiles
			const ncoord = coord.normalize();
			// we already have the tile, or it's currently pending
			if (this.has(ncoord) || this.isPending(ncoord)) {
				return;
			}
			// create the new tile
			const tile = new Tile(ncoord);
			// add tile to pending array
			this.pending.set(ncoord.hash, tile);
			// emit request
			this.layer.emit(EventType.TILE_REQUEST, new TileEvent(this.layer, tile));
			// request tile
			this.layer.requestTile(ncoord, (err, data) => {
				// remove tile from pending
				this.pending.delete(ncoord.hash);
				// check err
				if (err !== null) {
					// add err
					tile.err = err;
					// emit failure
					this.layer.emit(EventType.TILE_FAILURE, new TileEvent(this.layer, tile));
					// check if loaded
					checkIfLoaded(this);
					return;
				}
				// add data to the tile
				tile.data = data;
				// check if tile is stale
				if (this.isStale(plot, coord)) {
					// emit discard
					this.layer.emit(EventType.TILE_DISCARD, new TileEvent(this.layer, tile));
					// check if loaded
					checkIfLoaded(this);
					return;
				}
				// add to tile pyramid
				add(this, tile);
				// check if loaded
				checkIfLoaded(this);
			});
		});
	}

	/**
	 * If the tile exists in the pyramid, return it. Otherwise return the
	 * closest available tile, along with the offset and relative scale. If
	 * no ancestor exists, return undefined.
	 *
	 * @return {Tile} The tile that closest matches the provided coord.
	 */
	getAvailableLOD(coord) {
		const ncoord = coord.normalize();
		// check if we have the tile
		if (this.has(ncoord)) {
			return {
				coord: coord,
				tile: this.get(ncoord),
				offset: {
					x: 0,
					y: 0,
					extent: 1
				}
			};
		}
		// if not, take the closest ancestor
		const ancestor = this.getClosestAncestor(ncoord);
		if (ancestor) {
			return {
				coord: coord,
				tile: this.get(ancestor),
				offset: getLODOffset(ncoord, ancestor)
			};
		}
		return undefined;
	}
}

module.exports = TilePyramid;
<commit_msg>Increase default cache size.<commit_after>'use strict';

const defaultTo = require('lodash/defaultTo');
const throttle = require('lodash/throttle');
const LRU = require('lru-cache');
const Tile = require('../core/Tile');
const EventType = require('../event/EventType');
const TileEvent = require('../event/TileEvent');

// Constants

/**
 * Number of the tiles held in the pyramid.
 * @private
 * @constant {Number}
 */
const CACHE_SIZE = 256;

/**
 * Number of persistant zoom levels held in the pyramids.
 * @private
 * @constant {Number}
 */
const PERSISTANT_LEVELS = 4;

/**
 * Loaded event throttle in milliseconds.
 * @private
 * @constant {Number}
 */
const LOADED_THROTTLE_MS = 200;

// Private Methods

const getLODOffset = function(descendant, ancestor) {
	const scale = Math.pow(2, descendant.z - ancestor.z);
	const step = 1 / scale;
	const root = {
		x: ancestor.x * scale,
		y: ancestor.y * scale
	};
	return {
		x: (descendant.x - root.x) * step,
		y: (descendant.y - root.y) * step,
		extent: step
	};
};

const add = function(pyramid, tile) {
	if (tile.coord.z < pyramid.persistantLevels) {
		// persistant tiles
		if (pyramid.persistants.has(tile.coord.hash)) {
			throw `Tile of coord ${tile.coord.hash} already exists in the pyramid`;
		}
		pyramid.persistants.set(tile.coord.hash, tile);
	} else {
		// non-persistant tiles
		if (pyramid.tiles.has(tile.coord.hash)) {
			throw `Tile of coord ${tile.coord.hash} already exists in the pyramid`;
		}
		pyramid.tiles.set(tile.coord.hash, tile);
	}
	// store in level arrays
	if (!pyramid.levels.has(tile.coord.z)) {
		pyramid.levels.set(tile.coord.z, []);
	}
	pyramid.levels.get(tile.coord.z).push(tile);
	// emit add
	pyramid.layer.emit(EventType.TILE_ADD, new TileEvent(pyramid.layer, tile));
};

const remove = function(pyramid, tile) {
	if (tile.coord.z < pyramid.persistantLevels) {
		throw `Tile of coord ${tile.coord.hash} is flagged as persistant and cannot be removed`;
	}
	if (!pyramid.tiles.has(tile.coord.hash)) {
		throw `Tile of coord ${tile.coord.hash} does not exists in the pyramid`;
	}
	// remove from levels
	const level = pyramid.levels.get(tile.coord.z);
	level.splice(level.indexOf(tile), 1);
	if (level.length === 0) {
		pyramid.levels.delete(tile.coord.z);
	}
	// emit remove
	pyramid.layer.emit(EventType.TILE_REMOVE, new TileEvent(pyramid.layer, tile));
};

const sumPowerOfFour = function(n) {
	return (1/3) * (Math.pow(4, n) - 1);
};

const checkIfLoaded = throttle(function(pyramid) {
	// if no more pending tiles, emit load
	if (pyramid.pending.size === 0) {
		pyramid.layer.emit(EventType.LOAD, new TileEvent(pyramid.layer, null));
	}
}, LOADED_THROTTLE_MS);

/**
 * Class representing a pyramid of tiles.
 */
class TilePyramid {

	/**
	 * Instantiates a new Bounds object.
	 *
	 * @param {Layer} layer - The layer object.
	 * @param {Object} options - The pyramid options.
	 * @param {Number} options.cacheSize - The size of the tile cache.
	 * @param {Number} options.persistantLevels - The number of persistant levels in the pyramid.
	 */
	constructor(layer, options = {}) {
		if (!layer) {
			throw 'No layer parameter provided';
		}
		this.cacheSize = defaultTo(options.cacheSize, CACHE_SIZE);
		this.persistantLevels = defaultTo(options.persistantLevels, PERSISTANT_LEVELS);
		this.totalCapacity = this.cacheSize + sumPowerOfFour(this.persistantLevels);
		this.layer = layer;
		this.levels = new Map();
		this.persistants = new Map();
		this.pending = new Map();
		this.tiles = new LRU({
			max: this.cacheSize,
			dispose: (key, tile) => {
				remove(this, tile);
			}
		});
	}

	/**
	 * Test whether or not a coord is held in cache in the pyramid.
	 *
	 * @param {Coord} coord - The coord to test.
	 *
	 * @returns {boolean} Whether or not the coord exists in the pyramid.
	 */
	has(coord) {
		if (coord.z < this.persistantLevels) {
			return this.persistants.has(coord.hash);
		}
		return this.tiles.has(coord.hash);
	}

	/**
	 * Test whether or not a coord is currently pending.
	 *
	 * @param {Coord} coord - The coord to test.
	 *
	 * @returns {boolean} Whether or not the coord is currently pending.
	 */
	isPending(coord) {
		return this.pending.has(coord.hash);
	}

	/**
	 * Returns the tile matching the provided coord. If the tile does not
	 * exist, returns undefined.
	 *
	 * @param {Coord} coord - The coord of the tile to return.
	 *
	 * @returns {Tile} The tile object.
	 */
	get(coord) {
		if (coord.z < this.persistantLevels) {
			return this.persistants.get(coord.hash);
		}
		return this.tiles.get(coord.hash);
	}

	/**
	 * Returns the closest ancestor of the provided coord. If no ancestor
	 * exists in the pyramid, returns undefined.
	 *
	 * @param {Coord} coord - The coord of the tile.
	 *
	 * @return {Coord} The closest available ancestor of the provided coord.
	 */
	getClosestAncestor(coord) {
		// get ancestors levels, in descending order
		const levels = [...this.levels.keys()]
			.sort((a, b) => {
				// sort by key
				return b - a;
			}).filter(entry => {
				// filter by key
				return (entry < coord.z);
			});
		// check for closest ancestor
		for (let i=0; i<levels.length; i++) {
			const level = levels[i];
			const ancestor = coord.getAncestor(coord.z - level);
			if (this.has(ancestor)) {
				return ancestor;
			}
		}
		return undefined;
	}

	/**
	 * Returns true if the coordinate is no in the current or target
	 * viewport.
	 *
	 * @param {Plot} plot - The plot object.
	 * @param {Coord} coord - The coord to test.
	 *
	 * @returns {boolean} Whether or not the tile is stale.
	 */
	isStale(plot, coord) {
		// if zooming, use target zoom, if not use current zoom
		const animation = plot.zoomAnimation;
		const viewport = animation ? animation.targetViewport : plot.viewport;
		const zoom = animation ? animation.targetZoom : plot.zoom;
		return !viewport.isInView(plot.tileSize, coord, zoom);
	}

	/**
	 * Requests tiles for the provided coords. If the tiles already exist
	 * in the pyramid or is currently pending no request is made.
	 *
	 * @param {Plot} plot - The plot object.
	 * @param {Array} coords - The array of coords to request.
	 */
	requestTiles(plot, coords) {
		// request tiles
		coords.forEach(coord => {
			// get normalized coord, we use normalized coords for requests
			// so that we do not track / request the same tiles
			const ncoord = coord.normalize();
			// we already have the tile, or it's currently pending
			if (this.has(ncoord) || this.isPending(ncoord)) {
				return;
			}
			// create the new tile
			const tile = new Tile(ncoord);
			// add tile to pending array
			this.pending.set(ncoord.hash, tile);
			// emit request
			this.layer.emit(EventType.TILE_REQUEST, new TileEvent(this.layer, tile));
			// request tile
			this.layer.requestTile(ncoord, (err, data) => {
				// remove tile from pending
				this.pending.delete(ncoord.hash);
				// check err
				if (err !== null) {
					// add err
					tile.err = err;
					// emit failure
					this.layer.emit(EventType.TILE_FAILURE, new TileEvent(this.layer, tile));
					// check if loaded
					checkIfLoaded(this);
					return;
				}
				// add data to the tile
				tile.data = data;
				// check if tile is stale
				if (this.isStale(plot, coord)) {
					// emit discard
					this.layer.emit(EventType.TILE_DISCARD, new TileEvent(this.layer, tile));
					// check if loaded
					checkIfLoaded(this);
					return;
				}
				// add to tile pyramid
				add(this, tile);
				// check if loaded
				checkIfLoaded(this);
			});
		});
	}

	/**
	 * If the tile exists in the pyramid, return it. Otherwise return the
	 * closest available tile, along with the offset and relative scale. If
	 * no ancestor exists, return undefined.
	 *
	 * @return {Tile} The tile that closest matches the provided coord.
	 */
	getAvailableLOD(coord) {
		const ncoord = coord.normalize();
		// check if we have the tile
		if (this.has(ncoord)) {
			return {
				coord: coord,
				tile: this.get(ncoord),
				offset: {
					x: 0,
					y: 0,
					extent: 1
				}
			};
		}
		// if not, take the closest ancestor
		const ancestor = this.getClosestAncestor(ncoord);
		if (ancestor) {
			return {
				coord: coord,
				tile: this.get(ancestor),
				offset: getLODOffset(ncoord, ancestor)
			};
		}
		return undefined;
	}
}

module.exports = TilePyramid;
<|endoftext|>


<commit_before>'use strict';

var m = require('mithril'); // exposes mithril methods, useful for redraw etc.
var $osf = require('js/osfHelpers');
var iconmap = require('js/iconmap');
var lodashFind = require('lodash.find');
var mHelpers = require('js/mithrilHelpers');
var Raven = require('raven-js');

var withPagination = require('js/components/pagination').withPagination;

var QUICKFILES_PAGE_SIZE = 10;

var _buildUrl = function(page, user) {

    var query = {
        'page[size]': QUICKFILES_PAGE_SIZE,
        'page': page || 1,
        'version': '2.2',
    };

    return $osf.apiV2Url('users/' + user +  '/quickfiles/', { query: query});
};

var _getNextItems = function(ctrl, url, updatePagination) {
    if(ctrl.requestPending()) {
        return;
    }

    ctrl.quickFiles([]);
    ctrl.requestPending(true);

    var promise = m.request({
        method : 'GET',
        url : url,
        background : true,
        config: mHelpers.apiV2Config({withCredentials: window.contextVars.isOnRootDomain})
    });

    promise.then(
        function(result) {
            ctrl.requestPending(false);
            ctrl.quickFiles(result.data);
            updatePagination(result, url);
            m.redraw();
            return promise;
        }, function(xhr, textStatus, error) {
            ctrl.failed = true;
            ctrl.requestPending(false);
            m.redraw();
            Raven.captureMessage('Error retrieving quickfiles', {
                extra: {
                    url: url,
                    textStatus: textStatus,
                    error: error
                }
            });
        }
    );
};

var QuickFile = {

    controller: function(options) {
        var self = this;
        self.file = options.file;
        self.icon =  iconmap.file;
    },

    view: function(ctrl)  {
        var viewBase = window.location.origin + '/quickfiles';
        var viewUrl = ctrl.file.attributes.guid ? viewBase + '/' + ctrl.file.attributes.guid : viewBase + ctrl.file.attributes.path;
        return m('div', [
            m('li.project list-group-item list-group-item-node cite-container', [
                m('h4.list-group-item-heading', [
                    m('span.component-overflow.f-w-lg', {style: {lineHeight: 1.5, width: '100%'}}, [
                        m('span.col-md-8.project-statuses-lg', [
                            m('span', {class: ctrl.icon, style: 'padding-right: 5px;'}, ''),
                            m('a', {'href': viewUrl,
                                onclick : function () {
                                    $osf.trackClick('QuickFiles', 'view', 'view-quickfile-from-profile-page');
                                }
                            }, ctrl.file.attributes.name),
                        ])
                    ])
                ])
            ])
        ]);
    }
};

var QuickFiles = {

    controller: function (options) {
        var self = this;
        self.failed = false;
        self.user = options.user._id;
        self.isProfile = options.user.is_profile;

        self.quickFiles = m.prop([]);
        self.requestPending = m.prop(false);

        self.getCurrentQuickFiles = function _getCurrentQuickFiles(page) {
            if (!self.requestPending()) {
                var url = _buildUrl(page, self.user);
                return _getNextItems(self, url, options.updatePagination);
            }
        };
        self.getCurrentQuickFiles();
    },

    view: function (ctrl) {

        return m('ul.list-group m-md', [
            // Error message if the request fails
            ctrl.failed ? m('p', [
                    'Unable to retrieve quickfiles at this time. Please refresh the page or contact ',
                    m('a', {'href': 'mailto:support@osf.io'}, 'support@osf.io'),
                    ' if the problem persists.'
                ]) :

            // Show laoding icon while there is a pending request
            ctrl.requestPending() ?  m('.ball-pulse.ball-scale-blue.text-center', [m(''), m(''), m('')]) :

            // Display each quickfile
            [
                ctrl.quickFiles().length !== 0 ? ctrl.quickFiles().map(function(file) {
                    return m.component(QuickFile, {file: file});
                }) : ctrl.isProfile ?
                    m('div.help-block', {}, 'You have no public quickfiles')
                : m('div.help-block', {}, 'This user has no public quickfiles.')
            ]
        ]);
    }
};

var PaginationWrapper = withPagination({
    buildUrl: _buildUrl,
    getNextItems: _getNextItems
});

QuickFiles = new PaginationWrapper(QuickFiles);

module.exports = {
    QuickFiles: QuickFiles
};
<commit_msg>Remove quickfiles link in profile page<commit_after>'use strict';

var m = require('mithril'); // exposes mithril methods, useful for redraw etc.
var $osf = require('js/osfHelpers');
var iconmap = require('js/iconmap');
var lodashFind = require('lodash.find');
var mHelpers = require('js/mithrilHelpers');
var Raven = require('raven-js');

var withPagination = require('js/components/pagination').withPagination;

var QUICKFILES_PAGE_SIZE = 10;

var _buildUrl = function(page, user) {

    var query = {
        'page[size]': QUICKFILES_PAGE_SIZE,
        'page': page || 1,
        'version': '2.2',
    };

    return $osf.apiV2Url('users/' + user +  '/quickfiles/', { query: query});
};

var _getNextItems = function(ctrl, url, updatePagination) {
    if(ctrl.requestPending()) {
        return;
    }

    ctrl.quickFiles([]);
    ctrl.requestPending(true);

    var promise = m.request({
        method : 'GET',
        url : url,
        background : true,
        config: mHelpers.apiV2Config({withCredentials: window.contextVars.isOnRootDomain})
    });

    promise.then(
        function(result) {
            ctrl.requestPending(false);
            ctrl.quickFiles(result.data);
            updatePagination(result, url);
            m.redraw();
            return promise;
        }, function(xhr, textStatus, error) {
            ctrl.failed = true;
            ctrl.requestPending(false);
            m.redraw();
            Raven.captureMessage('Error retrieving quickfiles', {
                extra: {
                    url: url,
                    textStatus: textStatus,
                    error: error
                }
            });
        }
    );
};

var QuickFile = {

    controller: function(options) {
        var self = this;
        self.file = options.file;
        self.icon =  iconmap.file;
    },

    view: function(ctrl)  {
        var viewBase = window.location.origin;
        var viewUrl = ctrl.file.attributes.guid ? viewBase + '/' + ctrl.file.attributes.guid : viewBase + '/quickfiles' + ctrl.file.attributes.path;
        return m('div', [
            m('li.project list-group-item list-group-item-node cite-container', [
                m('h4.list-group-item-heading', [
                    m('span.component-overflow.f-w-lg', {style: {lineHeight: 1.5, width: '100%'}}, [
                        m('span.col-md-8.project-statuses-lg', [
                            m('span', {class: ctrl.icon, style: 'padding-right: 5px;'}, ''),
                            m('a', {'href': viewUrl,
                                onclick : function () {
                                    $osf.trackClick('QuickFiles', 'view', 'view-quickfile-from-profile-page');
                                }
                            }, ctrl.file.attributes.name),
                        ])
                    ])
                ])
            ])
        ]);
    }
};

var QuickFiles = {

    controller: function (options) {
        var self = this;
        self.failed = false;
        self.user = options.user._id;
        self.isProfile = options.user.is_profile;

        self.quickFiles = m.prop([]);
        self.requestPending = m.prop(false);

        self.getCurrentQuickFiles = function _getCurrentQuickFiles(page) {
            if (!self.requestPending()) {
                var url = _buildUrl(page, self.user);
                return _getNextItems(self, url, options.updatePagination);
            }
        };
        self.getCurrentQuickFiles();
    },

    view: function (ctrl) {

        return m('ul.list-group m-md', [
            // Error message if the request fails
            ctrl.failed ? m('p', [
                    'Unable to retrieve quickfiles at this time. Please refresh the page or contact ',
                    m('a', {'href': 'mailto:support@osf.io'}, 'support@osf.io'),
                    ' if the problem persists.'
                ]) :

            // Show laoding icon while there is a pending request
            ctrl.requestPending() ?  m('.ball-pulse.ball-scale-blue.text-center', [m(''), m(''), m('')]) :

            // Display each quickfile
            [
                ctrl.quickFiles().length !== 0 ? ctrl.quickFiles().map(function(file) {
                    return m.component(QuickFile, {file: file});
                }) : ctrl.isProfile ?
                    m('div.help-block', {}, 'You have no public quickfiles')
                : m('div.help-block', {}, 'This user has no public quickfiles.')
            ]
        ]);
    }
};

var PaginationWrapper = withPagination({
    buildUrl: _buildUrl,
    getNextItems: _getNextItems
});

QuickFiles = new PaginationWrapper(QuickFiles);

module.exports = {
    QuickFiles: QuickFiles
};
<|endoftext|>


<commit_before>import algoliasearch from 'algoliasearch/lite';
import algoliasearchHelper from 'algoliasearch-helper';
import forEach from 'lodash/collection/forEach';
import merge from 'lodash/object/merge';
import union from 'lodash/array/union';
import clone from 'lodash/lang/clone';
import {EventEmitter} from 'events';
import urlSyncWidget from './url-sync.js';
import version from './version.js';
import createHelpers from './createHelpers.js';

function defaultCreateURL() { return '#'; }

/**
 * @function instantsearch
 * @param  {string} options.appId The Algolia application ID
 * @param  {string} options.apiKey The Algolia search-only API key
 * @param  {string} options.indexName The name of the main index
 * @param  {string} [options.numberLocale] The locale used to display numbers. This will be passed
 * to Number.prototype.toLocaleString()
 * @param  {function} [options.searchFunction] A hook that will be called each time a search needs to be done, with the
 * helper as a parameter. It's your responsibility to call helper.search(). This option allows you to avoid doing
 * searches at page load for example.
 * @param  {Object} [options.searchParameters] Additional parameters to pass to
 * the Algolia API.
 * [Full documentation](https://community.algolia.com/algoliasearch-helper-js/docs/SearchParameters.html)
 * @param  {Object|boolean} [options.urlSync] Url synchronization configuration.
 * Setting to `true` will synchronize the needed search parameters with the browser url.
 * @param  {Object} [options.urlSync.mapping] Object used to define replacement query
 * parameter to use in place of another. Keys are current query parameters
 * and value the new value, e.g. `{ q: 'query' }`.
 * @param  {number} [options.urlSync.threshold] Idle time in ms after which a new
 * state is created in the browser history. The default value is 700. The url is always updated at each keystroke
 * but we only create a "previous search state" (activated when click on back button) every 700ms of idle time.
 * @param  {string[]} [options.urlSync.trackedParameters] Parameters that will
 * be synchronized in the URL. By default, it will track the query, all the
 * refinable attribute (facets and numeric filters), the index and the page.
 * [Full documentation](https://community.algolia.com/algoliasearch-helper-js/docs/SearchParameters.html)
 * @param  {boolean} [options.urlSync.useHash] If set to true, the url will be
 * hash based. Otherwise, it'll use the query parameters using the modern
 * history API.
 * @param  {function} [options.urlSync.getHistoryState] Pass this function to override the
 * default history API state we set to `null`. For example this could be used to force passing
 * {turbolinks: true} to the history API every time we update it.
 * @return {Object} the instantsearch instance
 */
class InstantSearch extends EventEmitter {
  constructor({
    appId = null,
    apiKey = null,
    indexName = null,
    numberLocale,
    searchParameters = {},
    urlSync = null,
    searchFunction
  }) {
    super();
    if (appId === null || apiKey === null || indexName === null) {
      let usage = `
Usage: instantsearch({
  appId: 'my_application_id',
  apiKey: 'my_search_api_key',
  indexName: 'my_index_name'
});`;
      throw new Error(usage);
    }

    let client = algoliasearch(appId, apiKey);
    client.addAlgoliaAgent('instantsearch.js ' + version);

    this.client = client;
    this.helper = null;
    this.indexName = indexName;
    this.searchParameters = {...searchParameters, index: indexName};
    this.widgets = [];
    this.templatesConfig = {
      helpers: createHelpers({numberLocale}),
      compileOptions: {}
    };

    if (searchFunction) {
      this._searchFunction = searchFunction;
    }

    this.urlSync = urlSync === true ? {} : urlSync;
  }

  /**
   * Add a widget
   * @param  {Object} [widget] The widget to add
   * @param  {function} [widget.render] Called after each search response has been received
   * @param  {function} [widget.getConfiguration] Let the widget update the configuration
   * of the search with new parameters
   * @param  {function} [widget.init] Called once before the first search
   * @return {Object} the added widget
   */
  addWidget(widget) {
    // Add the widget to the list of widget
    if (widget.render === undefined && widget.init === undefined) {
      throw new Error('Widget definition missing render or init method');
    }

    this.widgets.push(widget);
  }

  start() {
    if (!this.widgets) throw new Error('No widgets were added to instantsearch.js');

    if (this.urlSync) {
      let syncWidget = urlSyncWidget(this.urlSync);
      this._createURL = syncWidget.createURL.bind(syncWidget);
      this._createAbsoluteURL = relative => this._createURL(relative, {absolute: true});
      this._onHistoryChange = syncWidget.onHistoryChange.bind(syncWidget);
      this.widgets.push(syncWidget);
    } else {
      this._createURL = defaultCreateURL;
      this._createAbsoluteURL = defaultCreateURL;
      this._onHistoryChange = function() {};
    }

    this.searchParameters = this.widgets.reduce(enhanceConfiguration, this.searchParameters);

    let helper = algoliasearchHelper(
      this.client,
      this.searchParameters.index || this.indexName,
      this.searchParameters
    );

    if (this._searchFunction) {
      this._originalHelperSearch = helper.search.bind(helper);
      helper.search = this._wrappedSearch.bind(this);
    }

    this.helper = helper;

    this._init(helper.state, helper);

    helper.on('result', this._render.bind(this, helper));
    helper.search();
  }

  _wrappedSearch() {
    let helper = clone(this.helper);
    helper.search = this._originalHelperSearch;
    this._searchFunction(helper);
    return;
  }

  createURL(params) {
    if (!this._createURL) {
      throw new Error('You need to call start() before calling createURL()');
    }
    return this._createURL(this.helper.state.setQueryParameters(params));
  }

  _render(helper, results, state) {
    forEach(this.widgets, function(widget) {
      if (!widget.render) {
        return;
      }
      widget.render({
        templatesConfig: this.templatesConfig,
        results,
        state,
        helper,
        createURL: this._createAbsoluteURL
      });
    }, this);
    this.emit('render');
  }

  _init(state, helper) {
    const {_onHistoryChange, templatesConfig} = this;
    forEach(this.widgets, function(widget) {
      if (widget.init) {
        widget.init({
          state,
          helper,
          templatesConfig,
          createURL: this._createAbsoluteURL,
          onHistoryChange: _onHistoryChange
        });
      }
    }, this);
  }
}

function enhanceConfiguration(configuration, widgetDefinition) {
  if (!widgetDefinition.getConfiguration) return configuration;

  // Update searchParameters with the configuration from the widgets
  let partialConfiguration = widgetDefinition.getConfiguration(configuration);
  return merge(
    {},
    configuration,
    partialConfiguration,
    (a, b) => {
      if (Array.isArray(a)) {
        return union(a, b);
      }
    }
  );
}

export default InstantSearch;
<commit_msg>fix(meteorjs): lite build must point to the browser lite (#1097)<commit_after>// we use the fullpath to the lite build to solve a meteor.js issue:
// https://github.com/algolia/instantsearch.js/issues/1024#issuecomment-221618284
import algoliasearch from 'algoliasearch/src/browser/builds/algoliasearchLite.js';
import algoliasearchHelper from 'algoliasearch-helper';
import forEach from 'lodash/collection/forEach';
import merge from 'lodash/object/merge';
import union from 'lodash/array/union';
import clone from 'lodash/lang/clone';
import {EventEmitter} from 'events';
import urlSyncWidget from './url-sync.js';
import version from './version.js';
import createHelpers from './createHelpers.js';

function defaultCreateURL() { return '#'; }

/**
 * @function instantsearch
 * @param  {string} options.appId The Algolia application ID
 * @param  {string} options.apiKey The Algolia search-only API key
 * @param  {string} options.indexName The name of the main index
 * @param  {string} [options.numberLocale] The locale used to display numbers. This will be passed
 * to Number.prototype.toLocaleString()
 * @param  {function} [options.searchFunction] A hook that will be called each time a search needs to be done, with the
 * helper as a parameter. It's your responsibility to call helper.search(). This option allows you to avoid doing
 * searches at page load for example.
 * @param  {Object} [options.searchParameters] Additional parameters to pass to
 * the Algolia API.
 * [Full documentation](https://community.algolia.com/algoliasearch-helper-js/docs/SearchParameters.html)
 * @param  {Object|boolean} [options.urlSync] Url synchronization configuration.
 * Setting to `true` will synchronize the needed search parameters with the browser url.
 * @param  {Object} [options.urlSync.mapping] Object used to define replacement query
 * parameter to use in place of another. Keys are current query parameters
 * and value the new value, e.g. `{ q: 'query' }`.
 * @param  {number} [options.urlSync.threshold] Idle time in ms after which a new
 * state is created in the browser history. The default value is 700. The url is always updated at each keystroke
 * but we only create a "previous search state" (activated when click on back button) every 700ms of idle time.
 * @param  {string[]} [options.urlSync.trackedParameters] Parameters that will
 * be synchronized in the URL. By default, it will track the query, all the
 * refinable attribute (facets and numeric filters), the index and the page.
 * [Full documentation](https://community.algolia.com/algoliasearch-helper-js/docs/SearchParameters.html)
 * @param  {boolean} [options.urlSync.useHash] If set to true, the url will be
 * hash based. Otherwise, it'll use the query parameters using the modern
 * history API.
 * @param  {function} [options.urlSync.getHistoryState] Pass this function to override the
 * default history API state we set to `null`. For example this could be used to force passing
 * {turbolinks: true} to the history API every time we update it.
 * @return {Object} the instantsearch instance
 */
class InstantSearch extends EventEmitter {
  constructor({
    appId = null,
    apiKey = null,
    indexName = null,
    numberLocale,
    searchParameters = {},
    urlSync = null,
    searchFunction
  }) {
    super();
    if (appId === null || apiKey === null || indexName === null) {
      let usage = `
Usage: instantsearch({
  appId: 'my_application_id',
  apiKey: 'my_search_api_key',
  indexName: 'my_index_name'
});`;
      throw new Error(usage);
    }

    let client = algoliasearch(appId, apiKey);
    client.addAlgoliaAgent('instantsearch.js ' + version);

    this.client = client;
    this.helper = null;
    this.indexName = indexName;
    this.searchParameters = {...searchParameters, index: indexName};
    this.widgets = [];
    this.templatesConfig = {
      helpers: createHelpers({numberLocale}),
      compileOptions: {}
    };

    if (searchFunction) {
      this._searchFunction = searchFunction;
    }

    this.urlSync = urlSync === true ? {} : urlSync;
  }

  /**
   * Add a widget
   * @param  {Object} [widget] The widget to add
   * @param  {function} [widget.render] Called after each search response has been received
   * @param  {function} [widget.getConfiguration] Let the widget update the configuration
   * of the search with new parameters
   * @param  {function} [widget.init] Called once before the first search
   * @return {Object} the added widget
   */
  addWidget(widget) {
    // Add the widget to the list of widget
    if (widget.render === undefined && widget.init === undefined) {
      throw new Error('Widget definition missing render or init method');
    }

    this.widgets.push(widget);
  }

  start() {
    if (!this.widgets) throw new Error('No widgets were added to instantsearch.js');

    if (this.urlSync) {
      let syncWidget = urlSyncWidget(this.urlSync);
      this._createURL = syncWidget.createURL.bind(syncWidget);
      this._createAbsoluteURL = relative => this._createURL(relative, {absolute: true});
      this._onHistoryChange = syncWidget.onHistoryChange.bind(syncWidget);
      this.widgets.push(syncWidget);
    } else {
      this._createURL = defaultCreateURL;
      this._createAbsoluteURL = defaultCreateURL;
      this._onHistoryChange = function() {};
    }

    this.searchParameters = this.widgets.reduce(enhanceConfiguration, this.searchParameters);

    let helper = algoliasearchHelper(
      this.client,
      this.searchParameters.index || this.indexName,
      this.searchParameters
    );

    if (this._searchFunction) {
      this._originalHelperSearch = helper.search.bind(helper);
      helper.search = this._wrappedSearch.bind(this);
    }

    this.helper = helper;

    this._init(helper.state, helper);

    helper.on('result', this._render.bind(this, helper));
    helper.search();
  }

  _wrappedSearch() {
    let helper = clone(this.helper);
    helper.search = this._originalHelperSearch;
    this._searchFunction(helper);
    return;
  }

  createURL(params) {
    if (!this._createURL) {
      throw new Error('You need to call start() before calling createURL()');
    }
    return this._createURL(this.helper.state.setQueryParameters(params));
  }

  _render(helper, results, state) {
    forEach(this.widgets, function(widget) {
      if (!widget.render) {
        return;
      }
      widget.render({
        templatesConfig: this.templatesConfig,
        results,
        state,
        helper,
        createURL: this._createAbsoluteURL
      });
    }, this);
    this.emit('render');
  }

  _init(state, helper) {
    const {_onHistoryChange, templatesConfig} = this;
    forEach(this.widgets, function(widget) {
      if (widget.init) {
        widget.init({
          state,
          helper,
          templatesConfig,
          createURL: this._createAbsoluteURL,
          onHistoryChange: _onHistoryChange
        });
      }
    }, this);
  }
}

function enhanceConfiguration(configuration, widgetDefinition) {
  if (!widgetDefinition.getConfiguration) return configuration;

  // Update searchParameters with the configuration from the widgets
  let partialConfiguration = widgetDefinition.getConfiguration(configuration);
  return merge(
    {},
    configuration,
    partialConfiguration,
    (a, b) => {
      if (Array.isArray(a)) {
        return union(a, b);
      }
    }
  );
}

export default InstantSearch;
<|endoftext|>


<commit_before>const axios = require(`axios`);

export default itemIdentifier => axios.get(`items`, {
  baseURL: `https://track.bpost.be/btr/api/`,
  responseType: `json`,
  params: { itemIdentifier },
}).then(res => res.data.items[0])
.catch(e => e);
<commit_msg>:bug: Fix axios import for UMD build<commit_after>import axios from 'axios';

export default itemIdentifier => axios.get(`items`, {
  baseURL: `https://track.bpost.be/btr/api/`,
  responseType: `json`,
  params: { itemIdentifier },
}).then(res => res.data.items[0])
.catch(e => e);
<|endoftext|>


<commit_before>/*
 * Parsec
 * https://github.com/d-plaindoux/parsec
 *
 * Copyright (c) 2016 Didier Plaindoux
 * Licensed under the LGPL2 license.
 */

/*
 * Parsec: Direct Style Monadic Parser Combinators For The Real World
 *
 * http://research.microsoft.com/en-us/um/people/daan/download/papers/parsec-paper.pdf
 */

//import response from './response.js';

import  stream from '../stream/index.js';
import unit from '../data/unit.js';
import option from '../data/option.js';
import response from "./response";

/**
 * Parser class
 */
class Parser{

    // (Stream 'c -> number -> Response 'a 'c) -> Parser 'a 'c
    constructor(parse){
        this.parse = parse;
    }

    // Parser 'a 'c => ('a -> Parser 'b 'c) -> Parser 'b 'c
    flatmap(f) {
        return bind(this, f);
    }

    // Parser 'a 'c => ('a -> 'b) -> Parser 'b 'c
    map(f) {
        var self = this;

        return new Parser(function (input, index) {
            return self.parse(input, index).map(f);
        });
    }

    // Parser 'a 'c => ('a -> boolean) -> Parser 'a 'c
    filter(p) {
        var self = this;

        return new Parser(function (input, index) {
            return self.parse(input, index).filter(p);
        });
    }

    // Parser 'a 'c => Comparable 'a -> Parser 'a 'c
    match(v) {
        return this.filter(function (a) {
            return a === v;
        });
    }

    // Parser 'a 'c => Parser 'b 'c -> Parser ('a,'b) 'c
    then(p) {
        return this.flatmap(function (a) {
            return p.map(function (b) {
                return [a, b];
            });
        });
    }

    // Parser 'a 'c => Parser 'b 'c -> Parser 'a 'c
    thenLeft(p) {
        return this.then(p).map(function (r) {
            return r[0];
        });
    }

    // Parser 'a 'c => 'b -> Parser 'b 'c
    thenReturns(v) {
        return this.thenRight(returns(v));
    }

    // Parser 'a 'c => Parser 'b 'c -> Parser 'b 'c
    thenRight(p) {
        return this.then(p).map(function (r) {
            return r[1];
        });
    }

    // Parser 'a 'c -> Parser 'a 'c
    or(p) {
        return choice(this, p);
    }

    // Parser 'a 'c => unit -> Parser (Option 'a) 'c
    opt() {
        return this.map(option.some).or(returns(option.none()));
    }

    // Parser 'a 'c => unit -> Parser (List 'a) 'c
    rep() {
        return repeatable(this, function () {
            return true;
        }, function (l) {
            return l !== 0;
        });
    }

    // Parser 'a 'c => number -> Parser (List 'a) 'c
    occ(occurrence) {
        return repeatable(this, function (l) {
            return l < occurrence;
        }, function (l) {
            return l === occurrence;
        });
    }

    // Parser 'a 'c => unit -> Parser (List 'a) 'c
    optrep() {
        return repeatable(this, function () {
            return true;
        }, function () {
            return true;
        });
    }

    // Parser 'a 'c => Parser 'b 'a -> Parser 'b 'c
    chain(p) {
        var self = this;

        return new Parser(function (input, index) {
            return p.parse(stream.buffered(stream.ofParser(self, input)), index);
        });
    }
}

// Response 'a 'c -> ('a -> Parser 'b 'c) -> Response 'b 'c
function bindAccepted(accept_a, f) {
    return f(accept_a.value).parse(accept_a.input, accept_a.offset).fold(
        function (accept_b) {
            return response.accept(
                accept_b.value,
                accept_b.input,
                accept_b.offset,
                accept_a.consumed || accept_b.consumed
            );
        },
        function (reject_b) {
            return response.reject(
                accept_a.input.location(reject_b.offset),
                accept_a.consumed || reject_b.consumed
            );
        }
    );
}

// Parser 'a 'c -> ('a -> Parser 'b 'c) -> Parser 'b 'c
function bind(self, f) {
    return new Parser(function (input, index) {
        return self.parse(input, index).fold(
            function (accept_a) {
                return bindAccepted(accept_a, f);
            },
            function (reject_a) {
                return reject_a;
            }
        );
    });
}

// Parser 'a 'c -> Parser 'a 'c -> Parser 'a 'c
function choice(self, f) {
    return new Parser(function (input, index) {
        return self.parse(input, index).fold(
            function (accept) {
                return accept;
            },
            function (reject) {
                if (reject.consumed) {
                    return reject;
                } else {
                    try {
                        return f.parse(input, index);
                    } catch (e) {
                        throw e;
                    }
                }
            }
        );
    });
}

// Parser 'a 'c -> unit -> Parser (List 'a) 'c
function repeatable(self, occurrences, accept) {
    return new Parser(function (input, index) {
        var consumed = false,
            value = [],
            offset = index,
            current = self.parse(input, index);

        while (current.isAccepted() && occurrences(value.length)) {
            value.push(current.value);
            consumed = consumed || current.consumed;
            offset = current.offset;

            current = self.parse(input, offset);
        }

        if (accept(value.length)) {
            return response.accept(value, input, offset, consumed);
        }

        return response.reject(offset, consumed);
    });
}

/*
 * Builders
 */

// (Stream 'c -> number -> Response 'a 'c) -> Parser 'a 'c
function parse(p) {
    return new Parser(p);
}

// (('b -> Parser 'a 'c) * 'b)-> Parser 'a 'c
function lazy(p, parameters) {
    return new Parser(function (input, index) {
        return p.apply(null, parameters).parse(input, index);
    });
}

// 'a -> Parser 'a 'c
function returns(v) {
    return new Parser(function (input, index) {
        return response.accept(v, input, index, false);
    });
}

// unit -> Parser 'a 'c
function error() {
    return new Parser(function (input, index) {
        return response.reject(input.location(index), false);
    });
}

// unit -> Parser unit 'c
function eos() {
    return new Parser(function (input, index) {
        if (input.endOfStream(index)) {
            return response.accept(unit, input, index, false);
        } else {
            return response.reject(input.location(index), false);
        }
    });
}

// ('a -> boolean) -> Parser a 'c
function satisfy(predicate) {
    return new Parser(function (input, index) {
        return input.get(index).filter(predicate).map(function (value) {
            return response.accept(value, input, index + 1, true);
        }).lazyRecoverWith(function () {
            return response.reject(input.location(index), false);
        });
    });
}

// Parser 'a 'c -> Parser 'a 'c
function doTry(p) {
    return new Parser(function (input, index) {
        return p.parse(input, index).fold(
            function (accept) {
                return accept;
            },
            function (reject) {
                return response.reject(input.location(reject.offset), false);
            }
        );
    });
}

// unit -> Parser 'a 'c
function any() {
    return satisfy(function () {
        return true;
    });
}

// Parser 'a ? -> Parser 'a 'a
function not(p) {
    return doTry(p).then(error()).or(any());
}

// unit -> Parser char char
function digit() {
    return satisfy(function (v) {
        return '0' <= v && v <= '9';
    });
}

// unit -> Parser char char
function lowerCase() {
    return satisfy(function (v) {
        return 'a' <= v && v <= 'z';
    });
}

// unit -> Parser char char
function upperCase() {
    return satisfy(function (v) {
        return 'A' <= v && v <= 'Z';
    });
}

// unit -> Parser char char
function letter() {
    return satisfy(function (v) {
        return ('a' <= v && v <= 'z') || ('A' <= v && v <= 'Z');
    });
}

// char -> Parser char char
function char(c) {
    if (c.length !== 1) {
        throw new Error("Char parser must contains one character");
    }

    return satisfy(function (v) {
        return c === v;
    });
}

// char -> Parser char char
function notChar(c) {
    if (c.length !== 1) {
        throw new Error("Char parser must contains one character");
    }

    return satisfy(function (v) {
        return c !== v;
    });
}

// string -> Parser char char
function charIn(c) {
    return satisfy(function (v) {
        return c.indexOf(v) !== -1;
    });
}

// string -> Parser char char
function charNotIn(c) {
    return satisfy(function (v) {
        return c.indexOf(v) === -1;
    });
}

// string -> Parser string char
function string(s) {
    return new Parser(function (input, index) {
        if (input.subStreamAt(s.split(''), index)) {
            return response.accept(s, input, index + s.length, true);
        } else {
            return response.reject(input.location(index), false);
        }
    });
}

// string -> Parser string char
function notString(s) {
    return not(string(s));
}

// unit -> Parser char char
function charLiteral() {
    var anyChar = string("\\'").or(notChar("'"));
    return char("'").thenRight(anyChar).thenLeft(char("'"));
}

// unit -> Parser string char
function stringLiteral() {
    var anyChar = string('\\"').or(notChar('"'));
    return char('"').thenRight(anyChar.optrep()).thenLeft(char('"')).map(function (r) {
        return r.join('');
    });
}

// unit -> Parser number char
function numberLiteral() {
    // [-+]?\d+([.]\d+)?([eE][+-]?\d+)?
    var join = function (r) {
            return r.join('');
        },
        joinOrEmpty = function (r) {
            return r.map(join).orElse('');
        },
        digits = digit().rep().map(join),
        integer = charIn("+-").opt().then(digits).map(function (r) {
            return r[0].orElse('') + r[1];
        }),
        float = integer.then(char('.').then(digits).opt().map(joinOrEmpty)).then(charIn('eE').then(integer).opt().map(joinOrEmpty)).map(function (r) {
            return r[0][0] + r[0][1] + r[1];
        });

    return float.map(function (r) {
        return parseFloat(r, 10);
    });
}

export default {
    parse: parse,
    lazy: lazy,
    returns: returns,
    error: error(),
    eos: eos(),
    satisfy: satisfy,
    try: doTry,
    any: any(),
    digit: digit(),
    lowerCase: lowerCase(),
    upperCase: upperCase(),
    not: not,
    letter: letter(),
    notChar: notChar,
    char: char,
    charIn: charIn,
    charNotIn: charNotIn,
    string: string,
    notString: notString,
    charLiteral: charLiteral(),
    stringLiteral: stringLiteral(),
    numberLiteral: numberLiteral()
}<commit_msg>Correction of a throw<commit_after>/*
 * Parsec
 * https://github.com/d-plaindoux/parsec
 *
 * Copyright (c) 2016 Didier Plaindoux
 * Licensed under the LGPL2 license.
 */

/*
 * Parsec: Direct Style Monadic Parser Combinators For The Real World
 *
 * http://research.microsoft.com/en-us/um/people/daan/download/papers/parsec-paper.pdf
 */

import  stream from '../stream/index.js';
import unit from '../data/unit.js';
import option from '../data/option.js';
import response from "./response";

/**
 * Parser class
 */
class Parser{

    // (Stream 'c -> number -> Response 'a 'c) -> Parser 'a 'c
    constructor(parse){
        this.parse = parse;
    }

    // Parser 'a 'c => ('a -> Parser 'b 'c) -> Parser 'b 'c
    flatmap(f) {
        return bind(this, f);
    }

    // Parser 'a 'c => ('a -> 'b) -> Parser 'b 'c
    map(f) {
        var self = this;

        return new Parser(function (input, index) {
            return self.parse(input, index).map(f);
        });
    }

    // Parser 'a 'c => ('a -> boolean) -> Parser 'a 'c
    filter(p) {
        var self = this;

        return new Parser(function (input, index) {
            return self.parse(input, index).filter(p);
        });
    }

    // Parser 'a 'c => Comparable 'a -> Parser 'a 'c
    match(v) {
        return this.filter(function (a) {
            return a === v;
        });
    }

    // Parser 'a 'c => Parser 'b 'c -> Parser ('a,'b) 'c
    then(p) {
        return this.flatmap(function (a) {
            return p.map(function (b) {
                return [a, b];
            });
        });
    }

    // Parser 'a 'c => Parser 'b 'c -> Parser 'a 'c
    thenLeft(p) {
        return this.then(p).map(function (r) {
            return r[0];
        });
    }

    // Parser 'a 'c => 'b -> Parser 'b 'c
    thenReturns(v) {
        return this.thenRight(returns(v));
    }

    // Parser 'a 'c => Parser 'b 'c -> Parser 'b 'c
    thenRight(p) {
        return this.then(p).map(function (r) {
            return r[1];
        });
    }

    // Parser 'a 'c -> Parser 'a 'c
    or(p) {
        return choice(this, p);
    }

    // Parser 'a 'c => unit -> Parser (Option 'a) 'c
    opt() {
        return this.map(option.some).or(returns(option.none()));
    }

    // Parser 'a 'c => unit -> Parser (List 'a) 'c
    rep() {
        return repeatable(this, function () {
            return true;
        }, function (l) {
            return l !== 0;
        });
    }

    // Parser 'a 'c => number -> Parser (List 'a) 'c
    occ(occurrence) {
        return repeatable(this, function (l) {
            return l < occurrence;
        }, function (l) {
            return l === occurrence;
        });
    }

    // Parser 'a 'c => unit -> Parser (List 'a) 'c
    optrep() {
        return repeatable(this, function () {
            return true;
        }, function () {
            return true;
        });
    }

    // Parser 'a 'c => Parser 'b 'a -> Parser 'b 'c
    chain(p) {
        var self = this;

        return new Parser(function (input, index) {
            return p.parse(stream.buffered(stream.ofParser(self, input)), index);
        });
    }
}

// Response 'a 'c -> ('a -> Parser 'b 'c) -> Response 'b 'c
function bindAccepted(accept_a, f) {
    return f(accept_a.value).parse(accept_a.input, accept_a.offset).fold(
        function (accept_b) {
            return response.accept(
                accept_b.value,
                accept_b.input,
                accept_b.offset,
                accept_a.consumed || accept_b.consumed
            );
        },
        function (reject_b) {
            return response.reject(
                accept_a.input.location(reject_b.offset),
                accept_a.consumed || reject_b.consumed
            );
        }
    );
}

// Parser 'a 'c -> ('a -> Parser 'b 'c) -> Parser 'b 'c
function bind(self, f) {
    return new Parser(function (input, index) {
        return self.parse(input, index).fold(
            function (accept_a) {
                return bindAccepted(accept_a, f);
            },
            function (reject_a) {
                return reject_a;
            }
        );
    });
}

// Parser 'a 'c -> Parser 'a 'c -> Parser 'a 'c
function choice(self, f) {
    return new Parser(function (input, index) {
        return self.parse(input, index).fold(
            function (accept) {
                return accept;
            },
            function (reject) {
                if (reject.consumed) {
                    return reject;
                } else {
                    return f.parse(input, index);
                }
            }
        );
    });
}

// Parser 'a 'c -> unit -> Parser (List 'a) 'c
function repeatable(self, occurrences, accept) {
    return new Parser(function (input, index) {
        var consumed = false,
            value = [],
            offset = index,
            current = self.parse(input, index);

        while (current.isAccepted() && occurrences(value.length)) {
            value.push(current.value);
            consumed = consumed || current.consumed;
            offset = current.offset;

            current = self.parse(input, offset);
        }

        if (accept(value.length)) {
            return response.accept(value, input, offset, consumed);
        }

        return response.reject(offset, consumed);
    });
}

/*
 * Builders
 */

// (Stream 'c -> number -> Response 'a 'c) -> Parser 'a 'c
function parse(p) {
    return new Parser(p);
}

// (('b -> Parser 'a 'c) * 'b)-> Parser 'a 'c
function lazy(p, parameters) {
    return new Parser(function (input, index) {
        return p.apply(null, parameters).parse(input, index);
    });
}

// 'a -> Parser 'a 'c
function returns(v) {
    return new Parser(function (input, index) {
        return response.accept(v, input, index, false);
    });
}

// unit -> Parser 'a 'c
function error() {
    return new Parser(function (input, index) {
        return response.reject(input.location(index), false);
    });
}

// unit -> Parser unit 'c
function eos() {
    return new Parser(function (input, index) {
        if (input.endOfStream(index)) {
            return response.accept(unit, input, index, false);
        } else {
            return response.reject(input.location(index), false);
        }
    });
}

// ('a -> boolean) -> Parser a 'c
function satisfy(predicate) {
    return new Parser(function (input, index) {
        return input.get(index).filter(predicate).map(function (value) {
            return response.accept(value, input, index + 1, true);
        }).lazyRecoverWith(function () {
            return response.reject(input.location(index), false);
        });
    });
}

// Parser 'a 'c -> Parser 'a 'c
function doTry(p) {
    return new Parser(function (input, index) {
        return p.parse(input, index).fold(
            function (accept) {
                return accept;
            },
            function (reject) {
                return response.reject(input.location(reject.offset), false);
            }
        );
    });
}

// unit -> Parser 'a 'c
function any() {
    return satisfy(function () {
        return true;
    });
}

// Parser 'a ? -> Parser 'a 'a
function not(p) {
    return doTry(p).then(error()).or(any());
}

// unit -> Parser char char
function digit() {
    return satisfy(function (v) {
        return '0' <= v && v <= '9';
    });
}

// unit -> Parser char char
function lowerCase() {
    return satisfy(function (v) {
        return 'a' <= v && v <= 'z';
    });
}

// unit -> Parser char char
function upperCase() {
    return satisfy(function (v) {
        return 'A' <= v && v <= 'Z';
    });
}

// unit -> Parser char char
function letter() {
    return satisfy(function (v) {
        return ('a' <= v && v <= 'z') || ('A' <= v && v <= 'Z');
    });
}

// char -> Parser char char
function char(c) {
    if (c.length !== 1) {
        throw new Error("Char parser must contains one character");
    }

    return satisfy(function (v) {
        return c === v;
    });
}

// char -> Parser char char
function notChar(c) {
    if (c.length !== 1) {
        throw new Error("Char parser must contains one character");
    }

    return satisfy(function (v) {
        return c !== v;
    });
}

// string -> Parser char char
function charIn(c) {
    return satisfy(function (v) {
        return c.indexOf(v) !== -1;
    });
}

// string -> Parser char char
function charNotIn(c) {
    return satisfy(function (v) {
        return c.indexOf(v) === -1;
    });
}

// string -> Parser string char
function string(s) {
    return new Parser(function (input, index) {
        if (input.subStreamAt(s.split(''), index)) {
            return response.accept(s, input, index + s.length, true);
        } else {
            return response.reject(input.location(index), false);
        }
    });
}

// string -> Parser string char
function notString(s) {
    return not(string(s));
}

// unit -> Parser char char
function charLiteral() {
    var anyChar = string("\\'").or(notChar("'"));
    return char("'").thenRight(anyChar).thenLeft(char("'"));
}

// unit -> Parser string char
function stringLiteral() {
    var anyChar = string('\\"').or(notChar('"'));
    return char('"').thenRight(anyChar.optrep()).thenLeft(char('"')).map(function (r) {
        return r.join('');
    });
}

// unit -> Parser number char
function numberLiteral() {
    // [-+]?\d+([.]\d+)?([eE][+-]?\d+)?
    var join = function (r) {
            return r.join('');
        },
        joinOrEmpty = function (r) {
            return r.map(join).orElse('');
        },
        digits = digit().rep().map(join),
        integer = charIn("+-").opt().then(digits).map(function (r) {
            return r[0].orElse('') + r[1];
        }),
        float = integer.then(char('.').then(digits).opt().map(joinOrEmpty)).then(charIn('eE').then(integer).opt().map(joinOrEmpty)).map(function (r) {
            return r[0][0] + r[0][1] + r[1];
        });

    return float.map(function (r) {
        return parseFloat(r, 10);
    });
}

export default {
    parse: parse,
    lazy: lazy,
    returns: returns,
    error: error(),
    eos: eos(),
    satisfy: satisfy,
    try: doTry,
    any: any(),
    digit: digit(),
    lowerCase: lowerCase(),
    upperCase: upperCase(),
    not: not,
    letter: letter(),
    notChar: notChar,
    char: char,
    charIn: charIn,
    charNotIn: charNotIn,
    string: string,
    notString: notString,
    charLiteral: charLiteral(),
    stringLiteral: stringLiteral(),
    numberLiteral: numberLiteral()
}<|endoftext|>