<commit_before>angular.module('app').controller('AppController',
  function($scope, $rootScope, $translate,
           $cordovaDevice, $cordovaInAppBrowser, $cordovaStatusbar) {
  // Dev $rootScope.osVersion = '5';

  $rootScope.openExternalLink = function(link) {
    var options = {
      location: 'yes',
      clearcache: 'yes',
      toolbar: 'no',
    };

    $cordovaInAppBrowser.open(link, '_system', options);
    $cordovaInAppBrowser.close();
  };

  document.addEventListener('deviceready', function() {
    // CordovaPlugin available
    console.log('deviceready');

    $cordovaStatusbar.hide();
    $rootScope.TTS = TTS;
    $rootScope.osVersion = $cordovaDevice.getVersion();
    $rootScope.$apply();
  }, false);

  function pushSimulator() {
    navigatorMain.pushPage('views/simulator.html', {
      animation: 'none',
    });
    menu.closeMenu();
  }

  function pushAbout() {
    navigatorMain.pushPage('views/about.html', {
      animation: 'none',
    });
    menu.closeMenu();
  }

  function pushOptions() {
    navigatorMain.pushPage('views/options.html', {
      animation: 'none',
    });
    menu.closeMenu();
  }

  function pushColorPicker() {
    navigatorMain.pushPage('views/color-picker.html', {
      animation: 'none',
    });
    menu.closeMenu();
  }

  // Export functions
  $scope.redirectSimulator = function() {
    $scope.menu.setMainPage('navigators/navigatorMain.html', {
      callback: pushSimulator,
    });
  };

  $scope.redirectOptions = function() {
    $scope.menu.setMainPage('navigators/navigatorMain.html', {
      callback: pushOptions,
    });
  };

  $scope.redirectAbout = function() {
    $scope.menu.setMainPage('navigators/navigatorMain.html', {
      callback: pushAbout,
    });
  };

  $scope.redirectColorPicker = function() {
    $scope.menu.setMainPage('navigators/navigatorMain.html', {
      callback: pushColorPicker,
    });
  };

  $scope.changeLanguage = function(locale) {
    $translate.use(locale);
    $scope.localeName = locale;
    if (localStorage) {
      localStorage.setItem('locale', locale);
    }
  };

  $scope.talk = function(message) {
    if ($rootScope.TTS) {
      $rootScope.TTS
        .speak({
          text: message.text,
          locale: message.locale,
          rate: 0.75,
        }, function() {
          console.log('success');
        }, function(err) {
          console.log(err);
        });
    }
  };

  // Init
  $scope.localeName = $translate.proposedLanguage();
  $scope.locales = $translate.getAvailableLanguageKeys();

  // TODO Load articles json file.
  $rootScope.topicsColorblindess = [
    {
      id: 1,
      label: 'INTRODUCTION_TITLE',
      description: 'INTRODUCTION_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
    {
      id: 2,
      label: 'DALTONISM_TITLE',
      description: 'DALTONISM_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
    {
      id: 3,
      label: 'DICROMATE_TITLE',
      description: 'DICROMATE_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
    {
      id: 4,
      label: 'TRICHROMATE_TITLE',
      description: 'TRICHROMATE_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
    {
      id: 5,
      label: 'ACHROMATE_TITLE',
      description: 'ACHROMATE_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
    {
      id: 6,
      label: 'ACQUIRED_TITLE',
      description: 'ACQUIRED_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
  ];
  $rootScope.topicsTests = [
    {
      id: 1,
      label: 'ISHIHARA_TITLE',
      description: 'ISHIHARA_CONTENT',
      image: './assets/plates/plate-1.jpg',
      more: 'ISHIHARA_MORE',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
    {
      id: 2,
      label: 'FARNSWORTH_TITLE',
      description: 'FARNSWORTH_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
  ];
});
<commit_msg>speak a little more faster<commit_after>angular.module('app').controller('AppController',
  function($scope, $rootScope, $translate,
           $cordovaDevice, $cordovaInAppBrowser, $cordovaStatusbar) {
  // Dev $rootScope.osVersion = '5';

  $rootScope.openExternalLink = function(link) {
    var options = {
      location: 'yes',
      clearcache: 'yes',
      toolbar: 'no',
    };

    $cordovaInAppBrowser.open(link, '_system', options);
    $cordovaInAppBrowser.close();
  };

  document.addEventListener('deviceready', function() {
    // CordovaPlugin available
    console.log('deviceready');

    $cordovaStatusbar.hide();
    $rootScope.TTS = TTS;
    $rootScope.osVersion = $cordovaDevice.getVersion();
    $rootScope.$apply();
  }, false);

  function pushSimulator() {
    navigatorMain.pushPage('views/simulator.html', {
      animation: 'none',
    });
    menu.closeMenu();
  }

  function pushAbout() {
    navigatorMain.pushPage('views/about.html', {
      animation: 'none',
    });
    menu.closeMenu();
  }

  function pushOptions() {
    navigatorMain.pushPage('views/options.html', {
      animation: 'none',
    });
    menu.closeMenu();
  }

  function pushColorPicker() {
    navigatorMain.pushPage('views/color-picker.html', {
      animation: 'none',
    });
    menu.closeMenu();
  }

  // Export functions
  $scope.redirectSimulator = function() {
    $scope.menu.setMainPage('navigators/navigatorMain.html', {
      callback: pushSimulator,
    });
  };

  $scope.redirectOptions = function() {
    $scope.menu.setMainPage('navigators/navigatorMain.html', {
      callback: pushOptions,
    });
  };

  $scope.redirectAbout = function() {
    $scope.menu.setMainPage('navigators/navigatorMain.html', {
      callback: pushAbout,
    });
  };

  $scope.redirectColorPicker = function() {
    $scope.menu.setMainPage('navigators/navigatorMain.html', {
      callback: pushColorPicker,
    });
  };

  $scope.changeLanguage = function(locale) {
    $translate.use(locale);
    $scope.localeName = locale;
    if (localStorage) {
      localStorage.setItem('locale', locale);
    }
  };

  $scope.talk = function(message) {
    if ($rootScope.TTS) {
      $rootScope.TTS
        .speak({
          text: message.text,
          locale: message.locale,
          rate: 0.80,
        }, function() {
          console.log('success');
        }, function(err) {
          console.log(err);
        });
    }
  };

  // Init
  $scope.localeName = $translate.proposedLanguage();
  $scope.locales = $translate.getAvailableLanguageKeys();

  // TODO Load articles json file.
  $rootScope.topicsColorblindess = [
    {
      id: 1,
      label: 'INTRODUCTION_TITLE',
      description: 'INTRODUCTION_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
    {
      id: 2,
      label: 'DALTONISM_TITLE',
      description: 'DALTONISM_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
    {
      id: 3,
      label: 'DICROMATE_TITLE',
      description: 'DICROMATE_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
    {
      id: 4,
      label: 'TRICHROMATE_TITLE',
      description: 'TRICHROMATE_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
    {
      id: 5,
      label: 'ACHROMATE_TITLE',
      description: 'ACHROMATE_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
    {
      id: 6,
      label: 'ACQUIRED_TITLE',
      description: 'ACQUIRED_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
  ];
  $rootScope.topicsTests = [
    {
      id: 1,
      label: 'ISHIHARA_TITLE',
      description: 'ISHIHARA_CONTENT',
      image: './assets/plates/plate-1.jpg',
      more: 'ISHIHARA_MORE',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
    {
      id: 2,
      label: 'FARNSWORTH_TITLE',
      description: 'FARNSWORTH_CONTENT',
      lastModified: '2016-10-31',
      createdAt: '2016-09-13',
    },
  ];
});
<|endoftext|>


<commit_before>import PARAMETERS from "store/config/parameters.yml";

import OfflinePlaybackWebSocketEndpoint from "store/websocket/websocket_offline";
import RealtimeWebSocketEndpoint from "store/websocket/websocket_realtime";
import MapDataWebSocketEndpoint from "store/websocket/websocket_map";
import PointCloudWebSocketEndpoint from "store/websocket/websocket_point_cloud";

// Returns the websocket server address based on the web server address.
// Follows the convention that the websocket is served on the same host/port
// as the web server.
function deduceWebsocketServerAddr(type) {
  const server = window.location.origin;
  const link = document.createElement("a");
  link.href = server;
  const protocol = location.protocol === "https:" ? "wss" : "ws";

  let path = "";
  switch (type) {
    case "map":
      path = "map";
      break;
    case "point_cloud":
      path = "pointcloud";
      break;
    case "sim_world":
      path = OFFLINE_PLAYBACK ? "RosPlayBack" : "websocket";
      break;
  }
  return `${protocol}://${link.hostname}:${PARAMETERS.server.port}/${path}`;
}

// NOTE: process.env.NODE_ENV will be set to "production" by webpack when
// invoked in production mode ("-p"). We rely on this to determine which
// websocket server to use.
const simWorldServerAddr = deduceWebsocketServerAddr("sim_world");
const WS = OFFLINE_PLAYBACK
  ? new OfflinePlaybackWebSocketEndpoint(simWorldServerAddr)
  : new RealtimeWebSocketEndpoint(simWorldServerAddr);
export default WS;

const mapServerAddr = deduceWebsocketServerAddr("map");
export const MAP_WS = new MapDataWebSocketEndpoint(mapServerAddr);

const pointCloudServerAddr = deduceWebsocketServerAddr("point_cloud");
export const POINT_CLOUD_WS = new PointCloudWebSocketEndpoint(pointCloudServerAddr);
<commit_msg>Dreamview: allow flexible ws port for offline mode<commit_after>import PARAMETERS from "store/config/parameters.yml";

import OfflinePlaybackWebSocketEndpoint from "store/websocket/websocket_offline";
import RealtimeWebSocketEndpoint from "store/websocket/websocket_realtime";
import MapDataWebSocketEndpoint from "store/websocket/websocket_map";
import PointCloudWebSocketEndpoint from "store/websocket/websocket_point_cloud";

// Returns the websocket server address based on the web server address.
// Follows the convention that the websocket is served on the same host/port
// as the web server.
function deduceWebsocketServerAddr(type) {
    const server = window.location.origin;
    const link = document.createElement("a");
    link.href = server;
    const protocol = location.protocol === "https:" ? "wss" : "ws";
    const port =
        process.env.NODE_ENV === "production" ? window.location.port : PARAMETERS.server.port;

    let path = "";
    switch (type) {
        case "map":
            path = "map";
            break;
        case "point_cloud":
            path = "pointcloud";
            break;
        case "sim_world":
            path = OFFLINE_PLAYBACK ? "RosPlayBack" : "websocket";
            break;
    }
    return `${protocol}://${link.hostname}:${port}/${path}`;
}

// NOTE: process.env.NODE_ENV will be set to "production" by webpack when
// invoked in production mode ("-p"). We rely on this to determine which
// websocket server to use.
const simWorldServerAddr = deduceWebsocketServerAddr("sim_world");
const WS = OFFLINE_PLAYBACK
    ? new OfflinePlaybackWebSocketEndpoint(simWorldServerAddr)
    : new RealtimeWebSocketEndpoint(simWorldServerAddr);
export default WS;

const mapServerAddr = deduceWebsocketServerAddr("map");
export const MAP_WS = new MapDataWebSocketEndpoint(mapServerAddr);

const pointCloudServerAddr = deduceWebsocketServerAddr("point_cloud");
export const POINT_CLOUD_WS = new PointCloudWebSocketEndpoint(pointCloudServerAddr);
<|endoftext|>


<commit_before>;((exports) => {
    "use strict";

    // https://mozilla.design/firefox/color/
    const FIREFOX_YELLOW_5 = "#FFBD4F";
    const FIREFOX_YELLOW_6 = "#FFA537";
    const FIREFOX_BLUE_3 = "#00DDFF";
    const FIREFOX_BLUE_4 = "#00B3F5";
    const FIREFOX_BLUE_5 = "#0290EE";

    const MS_PER_DAY = 24*60*60*1000;
    const MS_PER_WEEK = 7*MS_PER_DAY;
    const MS_PER_MONTH = 4*MS_PER_WEEK;

    const DEBUG = true;
    function debug(...args) { DEBUG && console.debug(...args); }

    function days(d) { return d * MS_PER_DAY; }
    function weeks(w) { return days(7 * w); }
    function months(m) { return weeks(4 * m); }

    const PRODUCT_FILTER = "&classification=Client%20Software&classification=Components&product=DevTools&product=Firefox&product=Core&product=Testing&product=Toolkit&product=WebExtensions";
    const queryString = getQueryString() + PRODUCT_FILTER;
    const chartStartDate = getChartStartDate();

    function getQueryString() {
        // e.g. "?foo=bar&baz=qux&/"
        let qs = window.location.search;
        if (qs.length <= 1) {
            return "";
        }
        const slash = (qs[qs.length - 1] === '/') ? -1 : undefined;
        return qs.slice(1, slash);
    }

    function getChartStartDate() {
      const CHART_START_PERIOD = months(3);
      const searchParams = parseQueryString(queryString);
      return (searchParams && searchParams.since) ||
             yyyy_mm_dd(new Date(Date.now() - CHART_START_PERIOD));

      function parseQueryString(qs) {
          // e.g. "foo=bar&baz=qux&"
          const kvs = {};
          const params = qs.split("&");
          for (let kv of params) {
              kv = kv.split("=", 2);
              const key = kv[0].toLowerCase();
              if (key.length === 0) {
                  return; // "&&"
              }
              const value = (kv.length > 1) ? decodeURIComponent(kv[1]) : null;
              kvs[key] = value;
          }
          return kvs;
      }
    }

    function getElementValue(id) {
        return document.getElementById(id).value;
    }

    function yyyy_mm_dd(date) {
        return date.toISOString().slice(0,10);
    }

    function drawChart(bugDates, openBugCounts, closedBugCounts) {
        bb.generate({
            data: {
                xs: {
                    "openBugCounts": "bugDates",
                    "closedBugCounts": "bugDates",
                },
                columns: [
                    ["bugDates", ...bugDates],
                    ["closedBugCounts", ...closedBugCounts],
                    ["openBugCounts", ...openBugCounts],
                ],
                names: {
                    "openBugCounts": "Open Bugs",
                    "closedBugCounts": "Closed Bugs",
                },
                types: {
                    "openBugCounts": "area",
                    "closedBugCounts": "area",
                },
                colors: {
                    "openBugCounts": FIREFOX_YELLOW_6,
                    "closedBugCounts": FIREFOX_BLUE_4,
                },
                groups: [["openBugCounts", "closedBugCounts"]],
                order: null,
            },
            axis: {
                x: {
                    type: "timeseries",
                    tick: {format: "%Y-%m-%d"},
                }
            },
        });
    }

    function createElement(tag, child) {
        const element = document.createElement(tag);
        if (typeof child !== "undefined") {
            if (typeof child !== "object") {
                child = document.createTextNode(child.toString());
            }
            element.appendChild(child);
        }
        return element;
    }

    function createLink(text, url) {
        const element = createElement("a", text);
        element.setAttribute("href", url);
        return element;
    }

    function setErrorText(msg) {
        let chart = document.getElementById("chart");
        chart.innerText = msg;
    }

    function searchAndPlotBugs() {
        const t0 = Date.now();
        debug(`searchAndPlotBugs: ${queryString}`);
        if (!queryString) {
            setErrorText("🙈 Zarro boogs found");
            return;
        }

        $bugzilla.searchBugs(queryString, (error, bugs) => {
            const t1 = Date.now();
            debug(`searchAndPlotBugs: ${t1 - t0} ms`);

            if (error) {
                setErrorText(`🤮 ${error.type}`);
                return;
            }

            if (bugs.length === 0) {
                setErrorText("🙈 Zarro boogs found");
                return;
            }

            let bugActivity = {};

            function openedBugOn(date) {
                let bugDate = bugActivity[date];
                if (bugDate) {
                    bugDate.opened++;
                } else { // is undefined
                    bugActivity[date] = {date: date, opened: 1, closed: 0};
                }
            }

            function closedBugOn(date) {
                let bugDate = bugActivity[date];
                if (bugDate) {
                    bugDate.closed++;
                } else { // is undefined
                    bugActivity[date] = {date: date, opened: 0, closed: 1};
                }
            }

            const bugList = document.getElementById("bugs");
            let bugListURL = `https://bugzilla.mozilla.org/buglist.cgi?bug_id=`;

            for (let bug of bugs) {
                let openDate = yyyy_mm_dd(bug.creationTime);
                if (openDate < chartStartDate) {
                    openDate = chartStartDate;
                }
                openedBugOn(openDate);

                if (bug.open) {
                    const bugURL = $bugzilla.makeURL(bug.id);
                    const bugRow = createElement("div");
                    bugRow.appendChild(createLink(`bug ${bug.id} - ${bug.summary}`, bugURL));
                    bugList.appendChild(bugRow);
                    bugListURL += `${bug.id},`;
                } else {
                    let closedDate = yyyy_mm_dd(bug.resolutionTime);
                    if (closedDate < chartStartDate) {
                        closedDate = chartStartDate;
                    }
                    closedBugOn(closedDate);
                }
            }

            const openLink = createLink("Open bug list in Bugzilla", bugListURL);
            openLink.classList.add('open-bugzilla');
            bugList.appendChild(openLink);

            let bugDates = [];
            let openBugCounts = [];
            let closedBugCounts = [];

            let openBugCount = 0;
            let closedBugCount = 0;

            bugActivity = _.sortBy(bugActivity, "date");
            for (let {date, opened, closed} of bugActivity) {
                bugDates.push(date);

                openBugCount += opened - closed;
                openBugCounts.push(openBugCount);

                // Don't display bugs closed before the start date.
                if (closedBugCounts.length == 0) {
                  closedBugCounts.push(closedBugCount);
                } else {
                  closedBugCount += closed;
                  closedBugCounts.push(closedBugCount);
                }
            }

            // Extend last bug count to today, so burndown ends on today.
            const today = yyyy_mm_dd(new Date());
            if (bugDates.length > 0 && _.last(bugDates) < today) {
                bugDates.push(today);
                openBugCounts.push(openBugCount);
                closedBugCounts.push(closedBugCount);
            }

            drawChart(bugDates, openBugCounts, closedBugCounts);

            function roundToTwoDecimals(f) {
              return Math.floor(f * 100) / 100;
            }

            let chartPeriodInMs = Date.parse(_.last(bugDates)) - Date.parse(_.first(bugDates));
            let chartPeriodInDays = Math.ceil(chartPeriodInMs / MS_PER_DAY);

            let initialClosedBugCount = _.first(closedBugCounts);
            let currentClosedBugCount = _.last(closedBugCounts);
            let bugsClosed = currentClosedBugCount - initialClosedBugCount;
            let bugsClosedPerDay = (chartPeriodInDays > 0) ? (bugsClosed / chartPeriodInDays) : 0;

            let initialOpenBugCount = _.first(openBugCounts);
            let currentOpenBugCount = _.last(openBugCounts);
            let bugsOpened = currentOpenBugCount - initialOpenBugCount + bugsClosed;
            let bugsOpenedPerDay = (chartPeriodInDays > 0) ? (bugsOpened / chartPeriodInDays) : 0;
            let bugsOpenedAndClosedPerDay = bugsClosedPerDay - bugsOpenedPerDay;

            console.log(`Progress: ${currentClosedBugCount} of ${currentOpenBugCount + currentClosedBugCount} bugs closed = ${roundToTwoDecimals(currentClosedBugCount / (currentOpenBugCount + currentClosedBugCount)) * 100}%`);
            console.log(`Velocity: ${bugsClosed} bugs closed (${initialClosedBugCount} -> ${currentClosedBugCount}) in ${chartPeriodInDays} days = ${roundToTwoDecimals(bugsClosedPerDay)} bugs closed per day`);
            console.log(`Velocity: ${bugsOpened} bugs opened (${initialOpenBugCount} -> ${currentOpenBugCount + bugsClosed}) / ${chartPeriodInDays} days = ${roundToTwoDecimals(bugsOpenedPerDay)} bugs opened per day`);

            function logForecast(desc, bugsClosedPerDay) {
              if (bugsClosedPerDay > 0) {
                let daysToZeroOpenBugs = Math.ceil(currentOpenBugCount / bugsClosedPerDay);
                let msToZeroOpenBugs = daysToZeroOpenBugs * MS_PER_DAY;
                let dateOfZeroOpenBugs = new Date(Date.now() + msToZeroOpenBugs);
                let ymdOfZeroOpenBugs = yyyy_mm_dd(dateOfZeroOpenBugs);
                console.log(`${desc}: ${currentOpenBugCount} open bugs / ${roundToTwoDecimals(bugsClosedPerDay)} bugs closed per day = ${daysToZeroOpenBugs} days -> ${ymdOfZeroOpenBugs}`);
              } else {
                console.log(`${desc}: ${currentOpenBugCount} open bugs / ${roundToTwoDecimals(bugsClosedPerDay)} bugs closed per day -> Infinity`);
              }
            }

            logForecast("Forecast min", bugsClosedPerDay);
            logForecast("Forecast max", bugsOpenedAndClosedPerDay);
        });
    }

    searchAndPlotBugs();

    const title = queryString.split("&").join(", ");
    document.title = `Burning up: ${title}`;
})(this);
<commit_msg>Move some inner functions to the end of their outer function<commit_after>;((exports) => {
    "use strict";

    // https://mozilla.design/firefox/color/
    const FIREFOX_YELLOW_5 = "#FFBD4F";
    const FIREFOX_YELLOW_6 = "#FFA537";
    const FIREFOX_BLUE_3 = "#00DDFF";
    const FIREFOX_BLUE_4 = "#00B3F5";
    const FIREFOX_BLUE_5 = "#0290EE";

    const MS_PER_DAY = 24*60*60*1000;
    const MS_PER_WEEK = 7*MS_PER_DAY;
    const MS_PER_MONTH = 4*MS_PER_WEEK;

    const DEBUG = true;
    function debug(...args) { DEBUG && console.debug(...args); }

    function days(d) { return d * MS_PER_DAY; }
    function weeks(w) { return days(7 * w); }
    function months(m) { return weeks(4 * m); }

    const PRODUCT_FILTER = "&classification=Client%20Software&classification=Components&product=DevTools&product=Firefox&product=Core&product=Testing&product=Toolkit&product=WebExtensions";
    const queryString = getQueryString() + PRODUCT_FILTER;
    const chartStartDate = getChartStartDate();

    function getQueryString() {
        // e.g. "?foo=bar&baz=qux&/"
        let qs = window.location.search;
        if (qs.length <= 1) {
            return "";
        }
        const slash = (qs[qs.length - 1] === '/') ? -1 : undefined;
        return qs.slice(1, slash);
    }

    function getChartStartDate() {
      const CHART_START_PERIOD = months(3);
      const searchParams = parseQueryString(queryString);
      return (searchParams && searchParams.since) ||
             yyyy_mm_dd(new Date(Date.now() - CHART_START_PERIOD));

      function parseQueryString(qs) {
          // e.g. "foo=bar&baz=qux&"
          const kvs = {};
          const params = qs.split("&");
          for (let kv of params) {
              kv = kv.split("=", 2);
              const key = kv[0].toLowerCase();
              if (key.length === 0) {
                  return; // "&&"
              }
              const value = (kv.length > 1) ? decodeURIComponent(kv[1]) : null;
              kvs[key] = value;
          }
          return kvs;
      }
    }

    function getElementValue(id) {
        return document.getElementById(id).value;
    }

    function yyyy_mm_dd(date) {
        return date.toISOString().slice(0,10);
    }

    function drawChart(bugDates, openBugCounts, closedBugCounts) {
        bb.generate({
            data: {
                xs: {
                    "openBugCounts": "bugDates",
                    "closedBugCounts": "bugDates",
                },
                columns: [
                    ["bugDates", ...bugDates],
                    ["closedBugCounts", ...closedBugCounts],
                    ["openBugCounts", ...openBugCounts],
                ],
                names: {
                    "openBugCounts": "Open Bugs",
                    "closedBugCounts": "Closed Bugs",
                },
                types: {
                    "openBugCounts": "area",
                    "closedBugCounts": "area",
                },
                colors: {
                    "openBugCounts": FIREFOX_YELLOW_6,
                    "closedBugCounts": FIREFOX_BLUE_4,
                },
                groups: [["openBugCounts", "closedBugCounts"]],
                order: null,
            },
            axis: {
                x: {
                    type: "timeseries",
                    tick: {format: "%Y-%m-%d"},
                }
            },
        });
    }

    function createElement(tag, child) {
        const element = document.createElement(tag);
        if (typeof child !== "undefined") {
            if (typeof child !== "object") {
                child = document.createTextNode(child.toString());
            }
            element.appendChild(child);
        }
        return element;
    }

    function createLink(text, url) {
        const element = createElement("a", text);
        element.setAttribute("href", url);
        return element;
    }

    function setErrorText(msg) {
        let chart = document.getElementById("chart");
        chart.innerText = msg;
    }

    function searchAndPlotBugs() {
        const t0 = Date.now();
        debug(`searchAndPlotBugs: ${queryString}`);
        if (!queryString) {
            setErrorText("🙈 Zarro boogs found");
            return;
        }

        $bugzilla.searchBugs(queryString, (error, bugs) => {
            const t1 = Date.now();
            debug(`searchAndPlotBugs: ${t1 - t0} ms`);

            if (error) {
                setErrorText(`🤮 ${error.type}`);
                return;
            }

            if (bugs.length === 0) {
                setErrorText("🙈 Zarro boogs found");
                return;
            }

            let bugActivity = {};

            function openedBugOn(date) {
                let bugDate = bugActivity[date];
                if (bugDate) {
                    bugDate.opened++;
                } else { // is undefined
                    bugActivity[date] = {date: date, opened: 1, closed: 0};
                }
            }

            function closedBugOn(date) {
                let bugDate = bugActivity[date];
                if (bugDate) {
                    bugDate.closed++;
                } else { // is undefined
                    bugActivity[date] = {date: date, opened: 0, closed: 1};
                }
            }

            const bugList = document.getElementById("bugs");
            let bugListURL = `https://bugzilla.mozilla.org/buglist.cgi?bug_id=`;

            for (let bug of bugs) {
                let openDate = yyyy_mm_dd(bug.creationTime);
                if (openDate < chartStartDate) {
                    openDate = chartStartDate;
                }
                openedBugOn(openDate);

                if (bug.open) {
                    const bugURL = $bugzilla.makeURL(bug.id);
                    const bugRow = createElement("div");
                    bugRow.appendChild(createLink(`bug ${bug.id} - ${bug.summary}`, bugURL));
                    bugList.appendChild(bugRow);
                    bugListURL += `${bug.id},`;
                } else {
                    let closedDate = yyyy_mm_dd(bug.resolutionTime);
                    if (closedDate < chartStartDate) {
                        closedDate = chartStartDate;
                    }
                    closedBugOn(closedDate);
                }
            }

            const openLink = createLink("Open bug list in Bugzilla", bugListURL);
            openLink.classList.add('open-bugzilla');
            bugList.appendChild(openLink);

            let bugDates = [];
            let openBugCounts = [];
            let closedBugCounts = [];

            let openBugCount = 0;
            let closedBugCount = 0;

            bugActivity = _.sortBy(bugActivity, "date");
            for (let {date, opened, closed} of bugActivity) {
                bugDates.push(date);

                openBugCount += opened - closed;
                openBugCounts.push(openBugCount);

                // Don't display bugs closed before the start date.
                if (closedBugCounts.length == 0) {
                  closedBugCounts.push(closedBugCount);
                } else {
                  closedBugCount += closed;
                  closedBugCounts.push(closedBugCount);
                }
            }

            // Extend last bug count to today, so burndown ends on today.
            const today = yyyy_mm_dd(new Date());
            if (bugDates.length > 0 && _.last(bugDates) < today) {
                bugDates.push(today);
                openBugCounts.push(openBugCount);
                closedBugCounts.push(closedBugCount);
            }

            drawChart(bugDates, openBugCounts, closedBugCounts);

            let chartPeriodInMs = Date.parse(_.last(bugDates)) - Date.parse(_.first(bugDates));
            let chartPeriodInDays = Math.ceil(chartPeriodInMs / MS_PER_DAY);

            let initialClosedBugCount = _.first(closedBugCounts);
            let currentClosedBugCount = _.last(closedBugCounts);
            let bugsClosed = currentClosedBugCount - initialClosedBugCount;
            let bugsClosedPerDay = (chartPeriodInDays > 0) ? (bugsClosed / chartPeriodInDays) : 0;

            let initialOpenBugCount = _.first(openBugCounts);
            let currentOpenBugCount = _.last(openBugCounts);
            let bugsOpened = currentOpenBugCount - initialOpenBugCount + bugsClosed;
            let bugsOpenedPerDay = (chartPeriodInDays > 0) ? (bugsOpened / chartPeriodInDays) : 0;
            let bugsOpenedAndClosedPerDay = bugsClosedPerDay - bugsOpenedPerDay;

            console.log(`Progress: ${currentClosedBugCount} of ${currentOpenBugCount + currentClosedBugCount} bugs closed = ${roundToTwoDecimals(currentClosedBugCount / (currentOpenBugCount + currentClosedBugCount)) * 100}%`);
            console.log(`Velocity: ${bugsClosed} bugs closed (${initialClosedBugCount} -> ${currentClosedBugCount}) in ${chartPeriodInDays} days = ${roundToTwoDecimals(bugsClosedPerDay)} bugs closed per day`);
            console.log(`Velocity: ${bugsOpened} bugs opened (${initialOpenBugCount} -> ${currentOpenBugCount + bugsClosed}) / ${chartPeriodInDays} days = ${roundToTwoDecimals(bugsOpenedPerDay)} bugs opened per day`);

            logForecast("Forecast min", bugsClosedPerDay);
            logForecast("Forecast max", bugsOpenedAndClosedPerDay);

            function roundToTwoDecimals(f) {
              return Math.floor(f * 100) / 100;
            }

            function logForecast(desc, bugsClosedPerDay) {
              if (bugsClosedPerDay > 0) {
                let daysToZeroOpenBugs = Math.ceil(currentOpenBugCount / bugsClosedPerDay);
                let msToZeroOpenBugs = daysToZeroOpenBugs * MS_PER_DAY;
                let dateOfZeroOpenBugs = new Date(Date.now() + msToZeroOpenBugs);
                let ymdOfZeroOpenBugs = yyyy_mm_dd(dateOfZeroOpenBugs);
                console.log(`${desc}: ${currentOpenBugCount} open bugs / ${roundToTwoDecimals(bugsClosedPerDay)} bugs closed per day = ${daysToZeroOpenBugs} days -> ${ymdOfZeroOpenBugs}`);
              } else {
                console.log(`${desc}: ${currentOpenBugCount} open bugs / ${roundToTwoDecimals(bugsClosedPerDay)} bugs closed per day -> Infinity`);
              }
            }
        });
    }

    searchAndPlotBugs();

    const title = queryString.split("&").join(", ");
    document.title = `Burning up: ${title}`;
})(this);
<|endoftext|>


<commit_before>'use strict';

// Contacts controller

var contactsApp = angular.module('contacts');

contactsApp.controller('ContactsController', ['$scope', '$stateParams', 'Authentication', 'Contacts', '$modal', '$log', '$location',
	function($scope, $stateParams, Authentication, Contacts, $modal, $log, $location) {

        this.authentication = Authentication;

        //$scope.linkToContact =  function(selectedContact,  $location){
        //    $location.path('contacts/' + response._id);
        //}

        $scope.getDetails = function(contact) {
            $location.path('contacts/' + contact._id);
        }
        //find a list of Contacts
        $scope.find = function() {
            $scope.contacts = Contacts.query();
        }
            // Open a modal window to Update a single contact record
            this.modalUpdate = function (size, selectedContact) {

                var modalInstance = $modal.open({
                    templateUrl: 'modules/contacts/views/edit-contacts.client.view.html',
                    controller: function($scope, $modalInstance, contact){
                        $scope.contact = contact;

                        $scope.ok = function () {

                            if (document.updateContactForm.$valid){
								$modalInstance.close($scope.contact);
                            }
                            $modalInstance.dismiss('cancel');
                        };

                        $scope.cancel = function () {
                            $modalInstance.dismiss('cancel');
                        };
                    },
                    size: size,
                    resolve: {
                        contact: function () {
                            return selectedContact;
                        }
                    }
                });

                modalInstance.result.then(function (selectedItem) {
                    $scope.selected = selectedItem;
                }, function () {
                    $log.info('Modal dismissed at: ' + new Date());
                });
            };
    }
]);

contactsApp.controller('ContactsCreateController', ['$scope', 'Contacts', '$location',
    function($scope, Contacts, $location) {
        // Create new Contact

        $scope.create = function() {
            // Create new Contact object
            var contact = new Contacts ({
                firstName: $scope.firstName,
                surname: $scope.surname,
                address: $scope.address,
                state: $scope.state,
                zipCode: $scope.zipCode,
                email: $scope.email,
                phone: $scope.phone,
                is_volunteer: $scope.is_volunteer,
                city: $scope.city
            });

            // Redirect after save
            contact.$save(function(response) {
                $location.path('contacts/' + response._id);

                // Clear form fields
                $scope.firstName = undefined;
                $scope.surname = undefined;
                $scope.address = undefined;
                $scope.state = undefined;
                $scope.zipCode = undefined;
                $scope.email = undefined;
                $scope.phone = undefined;
                $scope.is_volunteer = undefined;
                $scope.city = undefined;
            }, function(errorResponse) {
                $scope.error = errorResponse.data.message;
                console.log(errorResponse);
            });
        };
    }
]);

contactsApp.controller('ContactsUpdateController', ['$scope', 'Contacts', '$stateParams', '$modal',
    function($scope, Contacts, $stateParams, $modal) {

        // Update existing Contact
        $scope.update = function(updatedContact) {
        	var contact = updatedContact;

        	contact.$update(function() {
        	}, function(errorResponse) {
        		$scope.error = errorResponse.data.message;
        	});
        };

        // Open a modal window to delete a single contact record
        this.modalDelete = function (size, selectedContact) {

            var modalInstance = $modal.open({
                templateUrl: 'modules/contacts/views/delete-confirm.client.view.html',
                controller: function($scope, $modalInstance, contact){
                    $scope.contact = contact;

                    $scope.ok = function () {

                        if (document.updateContactForm.$valid){
                            $modalInstance.close($scope.contact);
                        }
                        $modalInstance.dismiss('cancel');
                    };

                    $scope.cancel = function () {
                        $modalInstance.dismiss('cancel');
                    };
                },
                size: size,
                resolve: {
                    contact: function () {
                        return selectedContact;
                    }
                }
            });

            modalInstance.result.then(function (selectedItem) {
                $scope.selected = selectedItem;
            }, function () {
                $log.info('Modal dismissed at: ' + new Date());
            });
        };

    }

]);

contactsApp.controller('ContactsViewController', [ '$scope', 'Contacts', '$stateParams', '$modal',
function ($scope, Contacts, $stateParams, $modal) {
    // Find existing Contact
    $scope.findOne = function () {
        $scope.contact = Contacts.get({
            contactId: $stateParams.contactId
        });
        var adoptions = Contacts.findAdoptedCats({contactId: $stateParams.contactId}, function() {
            $scope.contact.isAdopter = adoptions.length > 0;
        });
        console.log($scope.contact);
    };

    // Open a modal window to Update a single contact record
    this.modalUpdate = function (size, selectedContact) {

        var modalInstance = $modal.open({
            templateUrl: 'modules/contacts/views/edit-contacts.client.view.html',
            controller: function($scope, $modalInstance, contact){
                $scope.contact = contact;

                $scope.ok = function () {

                    if (document.updateContactForm.$valid){
                        $modalInstance.close($scope.contact);
                    }
                    $modalInstance.dismiss('cancel');
                };

                $scope.cancel = function () {
                    $modalInstance.dismiss('cancel');
                };
            },
            size: size,
            resolve: {
                contact: function () {
                    return selectedContact;
                }
            }
        });

        modalInstance.result.then(function (selectedItem) {
            $scope.selected = selectedItem;
        }, function () {
            $log.info('Modal dismissed at: ' + new Date());
        });
    };

    // Open a modal window to view a contact's adopted cats
    this.modalAdoptedCatsView = function (size, selectedContact) {

        var modalInstance = $modal.open({
            templateUrl: 'modules/contacts/views/adopted-cats.client.view.html',
            controller: function($scope, $modalInstance, contact){
                $scope.contact = contact;

                $scope.adoptions = Contacts.findAdoptedCats({contactId:contact._id});

                $scope.cancel = function () {
                    $modalInstance.dismiss('cancel');
                };
            },
            size: size,
            resolve: {
                contact: function () {
                    return selectedContact;
                }
            }
        });

        modalInstance.result.then(function (selectedItem) {
            $scope.selected = selectedItem;
        }, function () {
            $log.info('Modal dismissed at: ' + new Date());
        });
    };

}]);

contactsApp.directive('contactList', [function() {
    return {
        restrict: 'E',
        transclude: true,
        templateURL: 'modules/contacts/views/view-contacts.client.view.html',
        link: function(scope, element, attrs){

         }
    };

}]);

		//// Create new Contact
		//$scope.create = function() {
		//	// Create new Contact object
		//	var contact = new Contacts ({
         //       firstName: this.firstName,
		//		surName: this.surName,
         //       address: this.address,
         //       state: this.state,
         //       zipCode: this.zipCode,
         //       email: this.email,
         //       phone: this.phone,
         //       is_volunteer: this.is_volunteer,
         //       city: this.city
		//	});
        //
		//	// Redirect after save
		//	contact.$save(function(response) {
		//		$location.path('contacts/' + response._id);
        //
		//		// Clear form fields
         //       $scope.firstName = '';
         //       $scope.surName = '';
         //       $scope.address = '';
         //       $scope.state = '';
         //       $scope.zipCode = '';
         //       $scope.email = '';
         //       $scope.phone = '';
         //       $scope.is_volunteer = '';
         //       $scope.city = '';
         //   }, function(errorResponse) {
		//		$scope.error = errorResponse.data.message;
		//	});
		//};

		//// Remove existing Contact
		//$scope.remove = function(contact) {
		//	if ( contact ) { contact.$remove();
        //
		//		for (var i in $scope.contacts) {
		//			if ($scope.contacts [i] === contact) {
		//				$scope.contacts.splice(i, 1);
		//			}
		//		}
		//	} else {
		//		$scope.contact.$remove(function() {
		//			$location.path('contacts');
		//		});
		//	}
		//};
        //
		//// Update existing Contact
		//$scope.update = function() {
		//	var contact = $scope.contact;
        //
		//	contact.$update(function() {
		//		$location.path('contacts/' + contact._id);
		//	}, function(errorResponse) {
		//		$scope.error = errorResponse.data.message;
		//	});
		//};
        //
		//// Find existing Contact
		//$scope.findOne = function() {
		//	$scope.contact = Contacts.get({
		//		contactId: $stateParams.contactId
		//	});
		//};
<commit_msg>Im just commiting so i can switch to master branch<commit_after>'use strict';

// Contacts controller

var contactsApp = angular.module('contacts');

contactsApp.controller('ContactsController', ['$scope', '$stateParams', 'Authentication', 'Contacts', '$modal', '$log', '$location',
	function($scope, $stateParams, Authentication, Contacts, $modal, $log, $location) {

        this.authentication = Authentication;

        //$scope.linkToContact =  function(selectedContact,  $location){
        //    $location.path('contacts/' + response._id);
        //}

        $scope.getDetails = function(contact) {
            $location.path('contacts/' + contact._id);
        }
        //find a list of Contacts
        $scope.find = function() {
            $scope.contacts = Contacts.query();
        }
            // Open a modal window to Update a single contact record
            this.modalUpdate = function (size, selectedContact) {

                var modalInstance = $modal.open({
                    templateUrl: 'modules/contacts/views/edit-contacts.client.view.html',
                    controller: function($scope, $modalInstance, contact){
                        $scope.contact = contact;

                        $scope.ok = function () {

                            if (document.updateContactForm.$valid){
								$modalInstance.close($scope.contact);
                            }
                            $modalInstance.dismiss('cancel');
                        };

                        $scope.cancel = function () {
                            $modalInstance.dismiss('cancel');
                        };
                    },
                    size: size,
                    resolve: {
                        contact: function () {
                            return selectedContact;
                        }
                    }
                });

                modalInstance.result.then(function (selectedItem) {
                    $scope.selected = selectedItem;
                }, function () {
                    $log.info('Modal dismissed at: ' + new Date());
                });
            };
    }
]);

contactsApp.controller('ContactsCreateController', ['$scope', 'Contacts', '$location',
    function($scope, Contacts, $location) {
        // Create new Contact

        $scope.create = function() {
            // Create new Contact object
            var contact = new Contacts ({
                firstName: $scope.firstName,
                surname: $scope.surname,
                address: $scope.address,
                state: $scope.state,
                zipCode: $scope.zipCode,
                email: $scope.email,
                phone: $scope.phone,
                is_volunteer: $scope.is_volunteer,
                city: $scope.city
            });

            // Redirect after save
            contact.$save(function(response) {
                $location.path('contacts/' + response._id);

                // Clear form fields
                $scope.firstName = undefined;
                $scope.surname = undefined;
                $scope.address = undefined;
                $scope.state = undefined;
                $scope.zipCode = undefined;
                $scope.email = undefined;
                $scope.phone = undefined;
                $scope.is_volunteer = undefined;
                $scope.city = undefined;
            }, function(errorResponse) {
                $scope.error = errorResponse.data.message;
                console.log(errorResponse);
            });
        };
    }
]);

contactsApp.controller('ContactsUpdateController', ['$scope', 'Contacts', '$stateParams', '$modal', 'Dialogs',
    function($scope, Contacts, $stateParams, $modal, Dialogs) {

        // Update existing Contact
        $scope.update = function(updatedContact) {
        	var contact = updatedContact;

        	contact.$update(function() {
        	}, function(errorResponse) {
        		$scope.error = errorResponse.data.message;
        	});
        };

        // Open a modal window to delete a single contact record
        this.modalDelete = function (size, selectedContact) {

            var modalInstance = $modal.open({
                templateUrl: 'modules/contacts/views/delete-confirm.client.view.html',
                controller: function($scope, $modalInstance, contact){
                    $scope.contact = contact;

                    $scope.ok = function () {

                        if (document.updateContactForm.$valid){
                            $modalInstance.close($scope.contact);
                        }
                        $modalInstance.dismiss('cancel');
                    };

                    $scope.cancel = function () {
                        $modalInstance.dismiss('cancel');
                    };
                },
                size: size,
                resolve: {
                    contact: function () {
                        return selectedContact;
                    }
                }
            });

            modalInstance.result.then(function (selectedItem) {
                $scope.selected = selectedItem;
            }, function () {
                $log.info('Modal dismissed at: ' + new Date());
            });
        };

    }

]);

contactsApp.controller('ContactsViewController', [ '$scope', 'Contacts', '$stateParams', '$modal',
function ($scope, Contacts, $stateParams, $modal) {
    // Find existing Contact
    $scope.findOne = function () {
        $scope.contact = Contacts.get({
            contactId: $stateParams.contactId
        });
        var adoptions = Contacts.findAdoptedCats({contactId: $stateParams.contactId}, function() {
            $scope.contact.isAdopter = adoptions.length > 0;
        });
        console.log($scope.contact);
    };

    // Open a modal window to Update a single contact record
    this.modalUpdate = function (size, selectedContact) {

        var modalInstance = $modal.open({
            templateUrl: 'modules/contacts/views/edit-contacts.client.view.html',
            controller: function($scope, $modalInstance, contact){
                $scope.contact = contact;

                $scope.ok = function () {

                    if (document.updateContactForm.$valid){
                        $modalInstance.close($scope.contact);
                    }
                    $modalInstance.dismiss('cancel');
                };

                $scope.cancel = function () {
                    $modalInstance.dismiss('cancel');
                };
            },
            size: size,
            resolve: {
                contact: function () {
                    return selectedContact;
                }
            }
        });

        modalInstance.result.then(function (selectedItem) {
            $scope.selected = selectedItem;
        }, function () {
            $log.info('Modal dismissed at: ' + new Date());
        });
    };

    // Open a modal window to view a contact's adopted cats
    this.modalAdoptedCatsView = function (size, selectedContact) {

        var modalInstance = $modal.open({
            templateUrl: 'modules/contacts/views/adopted-cats.client.view.html',
            controller: function($scope, $modalInstance, contact){
                $scope.contact = contact;

                $scope.adoptions = Contacts.findAdoptedCats({contactId:contact._id});

                $scope.cancel = function () {
                    $modalInstance.dismiss('cancel');
                };
            },
            size: size,
            resolve: {
                contact: function () {
                    return selectedContact;
                }
            }
        });

        modalInstance.result.then(function (selectedItem) {
            $scope.selected = selectedItem;
        }, function () {
            $log.info('Modal dismissed at: ' + new Date());
        });
    };

}]);

contactsApp.directive('contactList', [function() {
    return {
        restrict: 'E',
        transclude: true,
        templateURL: 'modules/contacts/views/view-contacts.client.view.html',
        link: function(scope, element, attrs){

         }
    };

}]);

		//// Create new Contact
		//$scope.create = function() {
		//	// Create new Contact object
		//	var contact = new Contacts ({
         //       firstName: this.firstName,
		//		surName: this.surName,
         //       address: this.address,
         //       state: this.state,
         //       zipCode: this.zipCode,
         //       email: this.email,
         //       phone: this.phone,
         //       is_volunteer: this.is_volunteer,
         //       city: this.city
		//	});
        //
		//	// Redirect after save
		//	contact.$save(function(response) {
		//		$location.path('contacts/' + response._id);
        //
		//		// Clear form fields
         //       $scope.firstName = '';
         //       $scope.surName = '';
         //       $scope.address = '';
         //       $scope.state = '';
         //       $scope.zipCode = '';
         //       $scope.email = '';
         //       $scope.phone = '';
         //       $scope.is_volunteer = '';
         //       $scope.city = '';
         //   }, function(errorResponse) {
		//		$scope.error = errorResponse.data.message;
		//	});
		//};

		//// Remove existing Contact
		//$scope.remove = function(contact) {
		//	if ( contact ) { contact.$remove();
        //
		//		for (var i in $scope.contacts) {
		//			if ($scope.contacts [i] === contact) {
		//				$scope.contacts.splice(i, 1);
		//			}
		//		}
		//	} else {
		//		$scope.contact.$remove(function() {
		//			$location.path('contacts');
		//		});
		//	}
		//};
        //
		//// Update existing Contact
		//$scope.update = function() {
		//	var contact = $scope.contact;
        //
		//	contact.$update(function() {
		//		$location.path('contacts/' + contact._id);
		//	}, function(errorResponse) {
		//		$scope.error = errorResponse.data.message;
		//	});
		//};
        //
		//// Find existing Contact
		//$scope.findOne = function() {
		//	$scope.contact = Contacts.get({
		//		contactId: $stateParams.contactId
		//	});
		//};
<|endoftext|>


<commit_before>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

function onLaunched(launchData) {
  chrome.app.window.create('index.html', {
    width: 640,
    height: 800,
    frame: 'none'
  });
}

chrome.app.runtime.onLaunched.addListener(onLaunched);
<commit_msg>Adding back window decorations for scummvm.<commit_after>/*
 * Copyright (c) 2014 The Native Client Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

function onLaunched(launchData) {
  chrome.app.window.create('index.html', {
    width: 640,
    height: 800,
  });
}

chrome.app.runtime.onLaunched.addListener(onLaunched);
<|endoftext|>


<commit_before><commit_msg>#5404: page/product redirect changes.<commit_after><|endoftext|>


<commit_before>(function (toc) {
  var document = window.document;

  // prettyfy code
  window.prettyPrint();

  // script for filtering api item
  toc = document.getElementById('cjs-toc');

  if (!toc) {
    return;
  }

  var cjs, commentjsTocFilter;

  cjs = commentjsTocFilter = {
    toc: toc,
    lis: toc.getElementsByTagName('a'),
    names: [],
    r_name: /[^\.\(]*(?=(\(\))?$)/,
    input: document.getElementById('cjs-filter'),
    resetButton:  document.getElementById('cjs-search-reset'),

    // initialize filtering functionality
    init: function () {
      // populate names array with li items
      // and its searchable text
      cjs.forEach(cjs.lis, function (elem) {
        cjs.names.push({
          li: elem.parentNode,
          text: elem.innerText.match(cjs.r_name)[0]
        });
      });

      cjs.input.onclick = cjs.input.onchange = cjs.input.onkeydown = cjs.input.onkeyup = cjs.filter;
      cjs.resetButton.onclick = cjs.resetFilter;
    },

    // helper function to iterate arrays
    forEach: function (arr, callback) {
      var i, l = arr.length;
      for (i = 0; i < l; i += 1) {
        if (callback.call(arr[i], arr[i], i, arr) === false) {
          break;
        }
      }
      return arr;
    },

    // make sure to work with strings
    toString: String,

    // check if is an abbreviated search
    isABBR: function (str, abbr) {
      var letters = abbr.toUpperCase().split(''),
        first = letters.shift(),
        r_abbr = new RegExp('^[' + first.toLowerCase() + first + '][a-z]*' + letters.join('[a-z]*') + '[a-z]*$');

      return r_abbr.test(cjs.toString(str));
    },

    // calculate weight
    calcWeight: function (txt, search) {
      txt = cjs.toString(txt);
      search = cjs.toString(search);

      var i, j, l, score = 0, chunk = txt.toLowerCase();

      if (txt === search) {
        return 1;
      }

      if (!txt || !search) {
        return 0;
      }

      if (cjs.isABBR(txt, search)) {
        return 0.9;
      }

      for (i = 0, l = search.length; i < l; i += 1) {
        j = chunk.indexOf(search.charAt(i));
        if (j !== -1) {
          chunk = chunk.substring(j + 1);
          score += 1 / (j + 1);
        }
      }

      score = Math.max(score / l - Math.abs(txt.length - l) / txt.length / 2, 0);
      return score;
    },

    // optimize saving last search
    lastSearchText: '',

    // filters toc items
    filter: function () {
      var searchTxt = cjs.input.value,
        res = [];

      if (cjs.lastSearchText === searchTxt) {
        return;
      }

      if (searchTxt.length > 1) {
        cjs.forEach(cjs.names, function (name) {
          res.push({
            li: name.li,
            weight: cjs.calcWeight(name.text, searchTxt)
          });
        });

        // sort by matching weight
        res.sort(function (a, b) {
          return b.weight - a.weight;
        });

        cjs.forEach(res, function (obj) {
          toc.appendChild(obj.li);
        });

      // only reset when no search text at all
      } else if (!searchTxt) {
        cjs.forEach(cjs.names, function (name) {
          toc.appendChild(name.li);
        });
      }

      // save last search
      cjs.lastSearchText = searchTxt;
    },

    // resets filter
    resetFilter: function () {
      // reset only if there is a filter text
      if (cjs.input.value) {
        cjs.input.value = '';
        cjs.filter();
      }
    }
  };

  // init filterable toc
  commentjsTocFilter.init();
}());<commit_msg>small code tweak to have all vars at the top<commit_after>(function (window, toc) {
  var document = window.document,
    cjs,
    commentjsTocFilter;

  // prettyfy code
  window.prettyPrint();

  // script for filtering api item
  toc = document.getElementById('cjs-toc');

  if (!toc) {
    return;
  }

  cjs = commentjsTocFilter = {
    toc: toc,
    lis: toc.getElementsByTagName('a'),
    names: [],
    r_name: /[^\.\(]*(?=(\(\))?$)/,
    input: document.getElementById('cjs-filter'),
    resetButton:  document.getElementById('cjs-search-reset'),

    // initialize filtering functionality
    init: function () {
      // populate names array with li items
      // and its searchable text
      cjs.forEach(cjs.lis, function (elem) {
        cjs.names.push({
          li: elem.parentNode,
          text: elem.innerText.match(cjs.r_name)[0]
        });
      });

      cjs.input.onclick = cjs.input.onchange = cjs.input.onkeydown = cjs.input.onkeyup = cjs.filter;
      cjs.resetButton.onclick = cjs.resetFilter;
    },

    // helper function to iterate arrays
    forEach: function (arr, callback) {
      var i, l = arr.length;
      for (i = 0; i < l; i += 1) {
        if (callback.call(arr[i], arr[i], i, arr) === false) {
          break;
        }
      }
      return arr;
    },

    // make sure to work with strings
    toString: String,

    // check if is an abbreviated search
    isABBR: function (str, abbr) {
      var letters = abbr.toUpperCase().split(''),
        first = letters.shift(),
        r_abbr = new RegExp('^[' + first.toLowerCase() + first + '][a-z]*' + letters.join('[a-z]*') + '[a-z]*$');

      return r_abbr.test(cjs.toString(str));
    },

    // calculate weight
    calcWeight: function (txt, search) {
      txt = cjs.toString(txt);
      search = cjs.toString(search);

      var i, j, l, score = 0, chunk = txt.toLowerCase();

      if (txt === search) {
        return 1;
      }

      if (!txt || !search) {
        return 0;
      }

      if (cjs.isABBR(txt, search)) {
        return 0.9;
      }

      for (i = 0, l = search.length; i < l; i += 1) {
        j = chunk.indexOf(search.charAt(i));
        if (j !== -1) {
          chunk = chunk.substring(j + 1);
          score += 1 / (j + 1);
        }
      }

      score = Math.max(score / l - Math.abs(txt.length - l) / txt.length / 2, 0);
      return score;
    },

    // optimize saving last search
    lastSearchText: '',

    // filters toc items
    filter: function () {
      var searchTxt = cjs.input.value,
        res = [];

      if (cjs.lastSearchText === searchTxt) {
        return;
      }

      if (searchTxt.length > 1) {
        cjs.forEach(cjs.names, function (name) {
          res.push({
            li: name.li,
            weight: cjs.calcWeight(name.text, searchTxt)
          });
        });

        // sort by matching weight
        res.sort(function (a, b) {
          return b.weight - a.weight;
        });

        cjs.forEach(res, function (obj) {
          toc.appendChild(obj.li);
        });

      // only reset when no search text at all
      } else if (!searchTxt) {
        cjs.forEach(cjs.names, function (name) {
          toc.appendChild(name.li);
        });
      }

      // save last search
      cjs.lastSearchText = searchTxt;
    },

    // resets filter
    resetFilter: function () {
      // reset only if there is a filter text
      if (cjs.input.value) {
        cjs.input.value = '';
        cjs.filter();
      }
    }
  };

  // init filterable toc
  commentjsTocFilter.init();
}(window));<|endoftext|>


<commit_before>/**
 * 编译webpack
 */

const webpack = require("webpack");
const path = require('path');
let files = require('./files');
let mfs = require('./memoryfs')
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractCSS = new ExtractTextPlugin('css/module/[id]-one.css');
const extractLESS = new ExtractTextPlugin({
  filename: 'css/module/[id]-two.css'
});
const memory_file = require('./memory_file')
const log = require('./log')
let _ = require('lodash')

var fewebpack = {
  start: function () {
    log.log('开启webpack')
    let _this = this

    this.watching = undefined

    let pagejs = files.getPageJs();

    if (pagejs.length == 0) {
      return Promise.resolve()
    }

    let webpackconfig_entry = {};
    pagejs.forEach(v => {
      if (v.path.indexOf('./') != 0) {
        v.path = './' + v.path
      }
      webpackconfig_entry[v.name] = v.path;
    });

    //console.info(webpackconfig_entry);

    return new Promise((resolve, reject) => {

      let webpack_config = {
        resolve: {
          extensions: ['.ts', '.tsx', '.js', '.jsx']
        },
        // 配置对象
        entry: webpackconfig_entry,
        output: {
          path: path.join(global.workdir, 'bundle', 'js'),
          //publicPath: '/js',
          filename: '[name].js'
        },
        resolveLoader: {
          alias: {
            "style-loader": path.join(global.appdir, 'node_modules', 'style-loader'),
            "css-loader": path.join(global.appdir, 'node_modules', 'css-loader'),
            "less-loader": path.join(global.appdir, 'node_modules', 'less-loader'),
            "file-loader": path.join(global.appdir, 'node_modules', 'file-loader'),
            "babel-loader": path.join(global.appdir, 'node_modules', 'babel-loader'),
            "awesome-typescript-loader": path.join(global.appdir, 'node_modules', 'awesome-typescript-loader'),
            "raw-loader": path.join(global.appdir, 'node_modules', 'raw-loader'),
            "base64-image-loader": path.join(global.appdir, 'node_modules', 'base64-image-loader')
          }
        },
        module: {
          rules: [
          {
            test: /\.(hbs|txt|html)$/,
            use: 'raw-loader'
          },
          {
            test: /_base64\.(gif|png|jpg)$/,
            use: 'base64-image-loader'
          },
          {
            test: /\.css$/,
            use: extractCSS.extract({
              fallback: "style-loader",
              use: "css-loader"
            })
          },
          {
            test: /\.less$/i,
            use: extractLESS.extract([{
              loader: 'css-loader',
              options: {
                sourceMap: false
              }
            }, {
              loader: 'less-loader',
              options: {
                sourceMap: false
              }
            }])
          },
          {
            test: /(!_base64)\.(png|jpg|gif|jpeg)$/,
            use: [{
              loader: "file-loader",
              options: {
                outputPath: 'img/',
                //publicPath: 'img'
                name: '[hash:10].[ext]'
              }
            }]
          },
          {
            test: /\.tsx?$/,
            use: [{
              loader: "awesome-typescript-loader",
              options: {
                configFileName: 'feide.config.json'
              }
            }]
          }
          ]
        },
        devtool: 'inline-source-map',
        plugins: [
          extractCSS,
          extractLESS
        ]
      }
      //js babel
      if (global.config.js_babel) {
        webpack_config.module.rules.push({
          test: /\.js$/,
          exclude: /(node_modules|bower_components)/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: ['env'],
              //sourceRoot: global.appdir
              filename: path.join(global.appdir, 'js')
            }
          }
        })
      }

      //console.info(webpack_config);

      let compiler = webpack(webpack_config);

      compiler.outputFileSystem = mfs;

      this.watching = compiler.watch({
        aggregateTimeout: 500,
        //poll: 1000,
        ignored: /(node_modules|bundle)/
      }, (error, stats) => {
        //console.info(stats.toJson("minimal"));
        if (error == null) {
          log.log('webpack编译成功', 'green')
          resolve()
        } else {
          log.log('webpack编译失败', 'red')
          reject(error)
        }

        _this.makeModuleStyleFile()

      });

      //console.info(this.watching);

      // this.watching = compiler.watch({}, _.debounce((error, stats) => {
      //   //console.info(stats.toJson("minimal"));
      //   if (error == null) {
      //     log.log('webpack编译成功', 'green')
      //     resolve()
      //   } else {
      //     log.log('webpack编译失败', 'red')
      //     reject(error)
      //   }

      //   _this.makeModuleStyleFile()

      // },	500));
    })

  },
  stop: function () {
    let _this = this
    return new Promise((resolve) => {
      if (this.watching != undefined) {
        _this.watching.close(() => {
          log.log('关闭webpack')
          //console.info(_this.watching);

          setTimeout(function () {
            resolve()
          }, 500)

        });
      } else {
        resolve();
      }
    });
  },
  /**
   * 重启webpack
   *
   */
  restart() {
    log.log('重启webpack')
    return new Promise((resolve, reject) => {
      this.stop().then(() => {
        return this.start()
      }).then(() => {
        log.log('重启webpack成功', 'green')
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },
  readJS: function (pagename) {
    //console.info(pagename)
    try {
      return mfs.readFileSync(path.join(global.workdir, 'bundle', 'js', pagename + '.js'), 'utf-8')
    } catch (error) {
      //log.log(error.message, 'red')
      return null
    }
    //return ;
  },
  readCssBgimg: function (imgname) {
    return mfs.readFileSync(path.join(global.workdir, 'bundle', 'js', 'img', imgname));
  },
  /**
   * 生成模块css文件
   */
  makeModuleStyleFile: function () {
    mfs.readdir(path.join(global.workdir, 'bundle', 'js', 'css', 'module'), function (error, result) {
      if (error != undefined) {
        if (error.errno == 34) {
          return false
        }
        log.log('模块Less生成失败！ ' + error.message, 'red')
        console.info(error);
        return false;
      }
      let modulestyle = [];
      //console.info(111);
      //console.info(result);
      result.forEach(v => {
        modulestyle.push('/*' + v + '*/\n')
        modulestyle.push(mfs.readFileSync(path.join(global.workdir, 'bundle', 'js', 'css', 'module', v), 'utf-8'))
      })
      memory_file.modulestyle = modulestyle.join('')
      files.writeFileSync(path.join('css', '_partial', '_module_style.less'), memory_file.modulestyle)

    })
  },
  /**
   * 清除模块css文件
   */
  clearModuleStyleFile: function () {
    let files = mfs.readdirSync(path.join(global.workdir, 'bundle', 'js', 'css', 'module'))
    files.forEach(v => {
      mfs.unlinkSync(path.join(global.workdir, 'bundle', 'js', 'css', 'module', v))
    })
  }
}

module.exports = fewebpack;<commit_msg>添加模块搜索默认路径<commit_after>/**
 * 编译webpack
 */

const webpack = require("webpack");
const path = require('path');
let files = require('./files');
let mfs = require('./memoryfs')
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractCSS = new ExtractTextPlugin('css/module/[id]-one.css');
const extractLESS = new ExtractTextPlugin({
  filename: 'css/module/[id]-two.css'
});
const memory_file = require('./memory_file')
const log = require('./log')
let _ = require('lodash')

var fewebpack = {
  start: function () {
    log.log('开启webpack')
    let _this = this

    this.watching = undefined

    let pagejs = files.getPageJs();

    if (pagejs.length == 0) {
      return Promise.resolve()
    }

    let webpackconfig_entry = {};
    pagejs.forEach(v => {
      if (v.path.indexOf('./') != 0) {
        v.path = './' + v.path
      }
      webpackconfig_entry[v.name] = v.path;
    });

    //console.info(webpackconfig_entry);

    return new Promise((resolve, reject) => {

      let webpack_config = {
        resolve: {
          modules: [
            path.join(global.workdir, 'js', 'modules')
          ],
          extensions: ['.ts', '.tsx', '.js', '.jsx']
        },
        // 配置对象
        entry: webpackconfig_entry,
        output: {
          path: path.join(global.workdir, 'bundle', 'js'),
          //publicPath: '/js',
          filename: '[name].js'
        },
        resolveLoader: {
          alias: {
            "style-loader": path.join(global.appdir, 'node_modules', 'style-loader'),
            "css-loader": path.join(global.appdir, 'node_modules', 'css-loader'),
            "less-loader": path.join(global.appdir, 'node_modules', 'less-loader'),
            "file-loader": path.join(global.appdir, 'node_modules', 'file-loader'),
            "babel-loader": path.join(global.appdir, 'node_modules', 'babel-loader'),
            "awesome-typescript-loader": path.join(global.appdir, 'node_modules', 'awesome-typescript-loader'),
            "raw-loader": path.join(global.appdir, 'node_modules', 'raw-loader'),
            "base64-image-loader": path.join(global.appdir, 'node_modules', 'base64-image-loader')
          }
        },
        module: {
          rules: [
          {
            test: /\.(hbs|txt|html)$/,
            use: 'raw-loader'
          },
          {
            test: /_base64\.(gif|png|jpg)$/,
            use: 'base64-image-loader'
          },
          {
            test: /\.css$/,
            use: extractCSS.extract({
              fallback: "style-loader",
              use: "css-loader"
            })
          },
          {
            test: /\.less$/i,
            use: extractLESS.extract([{
              loader: 'css-loader',
              options: {
                sourceMap: false
              }
            }, {
              loader: 'less-loader',
              options: {
                sourceMap: false
              }
            }])
          },
          {
            test: /(!_base64)\.(png|jpg|gif|jpeg)$/,
            use: [{
              loader: "file-loader",
              options: {
                outputPath: 'img/',
                //publicPath: 'img'
                name: '[hash:10].[ext]'
              }
            }]
          },
          {
            test: /\.tsx?$/,
            use: [{
              loader: "awesome-typescript-loader",
              options: {
                configFileName: 'feide.config.json'
              }
            }]
          }
          ]
        },
        devtool: 'inline-source-map',
        plugins: [
          extractCSS,
          extractLESS
        ]
      }
      //js babel
      if (global.config.js_babel) {
        webpack_config.module.rules.push({
          test: /\.js$/,
          exclude: /(node_modules|bower_components)/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: ['env'],
              //sourceRoot: global.appdir
              filename: path.join(global.appdir, 'js')
            }
          }
        })
      }

      //console.info(webpack_config);

      let compiler = webpack(webpack_config);

      compiler.outputFileSystem = mfs;

      this.watching = compiler.watch({
        aggregateTimeout: 500,
        //poll: 1000,
        ignored: /(node_modules|bundle)/
      }, (error, stats) => {
        //console.info(stats.toJson("minimal"));
        if (error == null) {
          log.log('webpack编译成功', 'green')
          resolve()
        } else {
          log.log('webpack编译失败', 'red')
          reject(error)
        }

        _this.makeModuleStyleFile()

      });

      //console.info(this.watching);

      // this.watching = compiler.watch({}, _.debounce((error, stats) => {
      //   //console.info(stats.toJson("minimal"));
      //   if (error == null) {
      //     log.log('webpack编译成功', 'green')
      //     resolve()
      //   } else {
      //     log.log('webpack编译失败', 'red')
      //     reject(error)
      //   }

      //   _this.makeModuleStyleFile()

      // },	500));
    })

  },
  stop: function () {
    let _this = this
    return new Promise((resolve) => {
      if (this.watching != undefined) {
        _this.watching.close(() => {
          log.log('关闭webpack')
          //console.info(_this.watching);

          setTimeout(function () {
            resolve()
          }, 500)

        });
      } else {
        resolve();
      }
    });
  },
  /**
   * 重启webpack
   *
   */
  restart() {
    log.log('重启webpack')
    return new Promise((resolve, reject) => {
      this.stop().then(() => {
        return this.start()
      }).then(() => {
        log.log('重启webpack成功', 'green')
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },
  readJS: function (pagename) {
    //console.info(pagename)
    try {
      return mfs.readFileSync(path.join(global.workdir, 'bundle', 'js', pagename + '.js'), 'utf-8')
    } catch (error) {
      //log.log(error.message, 'red')
      return null
    }
    //return ;
  },
  readCssBgimg: function (imgname) {
    return mfs.readFileSync(path.join(global.workdir, 'bundle', 'js', 'img', imgname));
  },
  /**
   * 生成模块css文件
   */
  makeModuleStyleFile: function () {
    mfs.readdir(path.join(global.workdir, 'bundle', 'js', 'css', 'module'), function (error, result) {
      if (error != undefined) {
        if (error.errno == 34) {
          return false
        }
        log.log('模块Less生成失败！ ' + error.message, 'red')
        console.info(error);
        return false;
      }
      let modulestyle = [];
      //console.info(111);
      //console.info(result);
      result.forEach(v => {
        modulestyle.push('/*' + v + '*/\n')
        modulestyle.push(mfs.readFileSync(path.join(global.workdir, 'bundle', 'js', 'css', 'module', v), 'utf-8'))
      })
      memory_file.modulestyle = modulestyle.join('')
      files.writeFileSync(path.join('css', '_partial', '_module_style.less'), memory_file.modulestyle)

    })
  },
  /**
   * 清除模块css文件
   */
  clearModuleStyleFile: function () {
    let files = mfs.readdirSync(path.join(global.workdir, 'bundle', 'js', 'css', 'module'))
    files.forEach(v => {
      mfs.unlinkSync(path.join(global.workdir, 'bundle', 'js', 'css', 'module', v))
    })
  }
}

module.exports = fewebpack;
<|endoftext|>