<commit_before>/***
 * this is the content script, which will be injected in all pages and checks if the page
 * defines a <meta name="dashboard" /> directive. If so it will setup refresh timers and
 * scroll to defined positions
 */
(function (chrome, document, window) {

    /***
     * Check if the page is a dashboard enabled page
     * Check if we can inject content scripts dynamically in iframes
     * - if so, we can add a post receive message between these frames
     */

    var isIframe = window.parent !== window && window.parent !== null,
        isDashboard = !isIframe && document.querySelectorAll("meta[name='dashboard']").length > 0,
        frames = [],
        framesLoading = {},
        iFrameClient = {
            reload: function () {
                window.location.reload();
            },
            addCss: function (data) {
                var css;

                if (data && data.style) {
                    css = document.createElement("style");
                    css.type = "text/css";
                    css.innerText = data.style;
                } else if (data && data.styleUrl) {
                    css = document.createElement("link");
                    css.rel = "stylesheet";
                    css.type = "text/css";
                    css.href = data.styleUrl;
                }

                if (!css) {
                    console.error("addCss method received invalid data.", data);
                    return;
                }

                var head = document.getElementsByTagName("head")[0];
                head.appendChild(css);
            },
            scrollTo: function (position) {
                window.scrollTo(position.pageXOffset, position.pageYOffset);
            }
        },
        dashboardClient = {

            _getIFrameForWindow: function (window) {
                // find frame
                for (var i = 0; i < frames.length; i++) {
                    var frame = frames[i];

                    if (frame.contentWindow === window) {
                        // found the frame
                        // send by the iframe, after the content script has been injected
                        return {
                            frame: frame,
                            index: i
                        };
                    }
                }

                return null;
            },

            _getUniqueKey: function () {
                return "dashboard" + location.pathname;
            },

            _save: function (key, value) {
                var uniqueKey = this._getUniqueKey();

                var data = JSON.parse(localStorage.getItem(uniqueKey) || "{}");

                data[key] = value;
                localStorage.setItem(uniqueKey, JSON.stringify(data));
            },

            _get: function (key, defaultValue) {
                var uniqueKey = this._getUniqueKey();
                var data = JSON.parse(localStorage.getItem(uniqueKey) || "{}");

                return data[key] || defaultValue;
            },

            ready: function (data, event) {
                var frame = this._getIFrameForWindow(event.source);
                frame && processCssForFrame(frame.frame);

                framesLoading[frame.index] = false;

                var scrollPosition = this._get("frame_" + frame.index);
                if (scrollPosition) {
                    frame.frame.invoke("scrollTo", scrollPosition);
                }

            },

            scrolled: function (data, event) {

                if (!window.localStorage) {
                    return;
                }

                var frame = this._getIFrameForWindow(event.source);
                if (frame && framesLoading[frame.index] !== true) {
                    // save scroll position in localStorage
                    this._save("frame_" + frame.index, data);
                }
            }
        },
        client = isIframe ? iFrameClient : dashboardClient;

    if (isDashboard) {
        frames = Array.prototype.slice.call(document.querySelectorAll("iframe"));

        frames.forEach(function (frame, index) {
            framesLoading[index] = true;

            frame.invoke = function (method, data) {
                // TODO: we could also read the origin from the iframe
                frame.contentWindow.postMessage({
                    method: method,
                    data: data
                }, "*");
            };

            var x = parseInt(frame.getAttribute("data-scroll-x")) || 0,
                y = parseInt(frame.getAttribute("data-scroll-y")) || 0;

            if (x || y) {
                dashboardClient._save("frame_" + index, {
                    pageXOffset: x,
                    pageYOffset: y
                });
            }

            var refreshRate = parseInt(frame.getAttribute("data-refresh"));
            if (!isNaN(refreshRate)) {
                // a number was given in seconds
                setInterval(function () {
                    frame.invoke("reload");
                }, refreshRate * 1000);
            }

        });
    } else {
        // Notify the dashboard that the content script has been loaded
        // so the dashboard can inject us the css
        window.parent.postMessage({
            method: "ready"
        }, "*");

        window.addEventListener("scroll", function () {
            window.parent.postMessage({
                method: "scrolled",
                data: {
                    pageXOffset: window.pageXOffset,
                    pageYOffset: window.pageYOffset
                }
            }, "*");
        }, false);

    }

    window.addEventListener("message", function (event) {

        // TODO: check origin
        var data = event.data,
            method = client[data.method];

        if (/^_/.test(data.method || "")) {
            // private method
            return;
        }

        if (method) {
            // method is available in client
            method.call(client, data.data, event)
        } else {
            console.log("No handler for method '" + data.method + "' found!", event);
        }

    }, false);

    function processCssForFrame(frame) {
        var cssUri = frame.getAttribute("data-css"),
            css;

        if (cssUri === null) {
            return;
        }

        if (/^#/.test(cssUri)) {
            // css is references by id
            var scriptBlock = document.querySelector(cssUri);
            if (!scriptBlock) {
                console.error("References css block '" + cssUri + "' not found.");
                return;
            }

            css = {
                style: scriptBlock.innerText
            };

        } else {
            css = {
                styleUrl: cssUri
            };
        }

        frame.invoke("addCss", css);
    }

})(chrome, document, window);<commit_msg>fixed a null pointer exception<commit_after>/***
 * this is the content script, which will be injected in all pages and checks if the page
 * defines a <meta name="dashboard" /> directive. If so it will setup refresh timers and
 * scroll to defined positions
 */
(function (chrome, document, window) {

    /***
     * Check if the page is a dashboard enabled page
     * Check if we can inject content scripts dynamically in iframes
     * - if so, we can add a post receive message between these frames
     */

    var isIframe = window.parent !== window && window.parent !== null,
        isDashboard = !isIframe && document.querySelectorAll("meta[name='dashboard']").length > 0,
        frames = [],
        framesLoading = {},
        iFrameClient = {
            reload: function () {
                window.location.reload();
            },
            addCss: function (data) {
                var css;

                if (data && data.style) {
                    css = document.createElement("style");
                    css.type = "text/css";
                    css.innerText = data.style;
                } else if (data && data.styleUrl) {
                    css = document.createElement("link");
                    css.rel = "stylesheet";
                    css.type = "text/css";
                    css.href = data.styleUrl;
                }

                if (!css) {
                    console.error("addCss method received invalid data.", data);
                    return;
                }

                var head = document.getElementsByTagName("head")[0];
                head.appendChild(css);
            },
            scrollTo: function (position) {
                window.scrollTo(position.pageXOffset, position.pageYOffset);
            }
        },
        dashboardClient = {

            _getIFrameForWindow: function (window) {
                // find frame
                for (var i = 0; i < frames.length; i++) {
                    var frame = frames[i];

                    if (frame.contentWindow === window) {
                        // found the frame
                        // send by the iframe, after the content script has been injected
                        return {
                            frame: frame,
                            index: i
                        };
                    }
                }

                return null;
            },

            _getUniqueKey: function () {
                return "dashboard" + location.pathname;
            },

            _save: function (key, value) {
                var uniqueKey = this._getUniqueKey();

                var data = JSON.parse(localStorage.getItem(uniqueKey) || "{}");

                data[key] = value;
                localStorage.setItem(uniqueKey, JSON.stringify(data));
            },

            _get: function (key, defaultValue) {
                var uniqueKey = this._getUniqueKey();
                var data = JSON.parse(localStorage.getItem(uniqueKey) || "{}");

                return data[key] || defaultValue;
            },

            ready: function (data, event) {
                var frame = this._getIFrameForWindow(event.source);

                if (!frame) {
                    return;
                }

                processCssForFrame(frame.frame);

                framesLoading[frame.index] = false;

                var scrollPosition = this._get("frame_" + frame.index);
                if (scrollPosition) {
                    frame.frame.invoke("scrollTo", scrollPosition);
                }

            },

            scrolled: function (data, event) {

                if (!window.localStorage) {
                    return;
                }

                var frame = this._getIFrameForWindow(event.source);
                if (frame && framesLoading[frame.index] !== true) {
                    // save scroll position in localStorage
                    this._save("frame_" + frame.index, data);
                }
            }
        },
        client = isIframe ? iFrameClient : dashboardClient;

    if (isDashboard) {
        frames = Array.prototype.slice.call(document.querySelectorAll("iframe"));

        frames.forEach(function (frame, index) {
            framesLoading[index] = true;

            frame.invoke = function (method, data) {
                // TODO: we could also read the origin from the iframe
                frame.contentWindow.postMessage({
                    method: method,
                    data: data
                }, "*");
            };

            var x = parseInt(frame.getAttribute("data-scroll-x")) || 0,
                y = parseInt(frame.getAttribute("data-scroll-y")) || 0;

            if (x || y) {
                dashboardClient._save("frame_" + index, {
                    pageXOffset: x,
                    pageYOffset: y
                });
            }

            var refreshRate = parseInt(frame.getAttribute("data-refresh"));
            if (!isNaN(refreshRate)) {
                // a number was given in seconds
                setInterval(function () {
                    frame.invoke("reload");
                }, refreshRate * 1000);
            }

        });
    } else {
        // Notify the dashboard that the content script has been loaded
        // so the dashboard can inject us the css
        window.parent.postMessage({
            method: "ready"
        }, "*");

        window.addEventListener("scroll", function () {
            window.parent.postMessage({
                method: "scrolled",
                data: {
                    pageXOffset: window.pageXOffset,
                    pageYOffset: window.pageYOffset
                }
            }, "*");
        }, false);

    }

    window.addEventListener("message", function (event) {

        // TODO: check origin
        var data = event.data,
            method = client[data.method];

        if (/^_/.test(data.method || "")) {
            // private method
            return;
        }

        if (method) {
            // method is available in client
            method.call(client, data.data, event)
        } else {
            console.log("No handler for method '" + data.method + "' found!", event);
        }

    }, false);

    function processCssForFrame(frame) {
        var cssUri = frame.getAttribute("data-css"),
            css;

        if (cssUri === null) {
            return;
        }

        if (/^#/.test(cssUri)) {
            // css is references by id
            var scriptBlock = document.querySelector(cssUri);
            if (!scriptBlock) {
                console.error("References css block '" + cssUri + "' not found.");
                return;
            }

            css = {
                style: scriptBlock.innerText
            };

        } else {
            css = {
                styleUrl: cssUri
            };
        }

        frame.invoke("addCss", css);
    }

})(chrome, document, window);<|endoftext|>


<commit_before>InboxSDK.load('1', 'sdk_Hackotron-BE_a4e83dfe8a').then(function(sdk){

	// the SDK has been loaded, now do something with it!
	sdk.Compose.registerComposeViewHandler(function(composeView){

sdk.Conversations.registerMessageViewHandler(function(messageView){
		//window.alert("View Messages");

  		messageView.on('load', function(event) {
  			if(event.messageView.getViewState() == "EXPANDED")
  			{
  				var files = event.messageView.getFileAttachmentCardViews();

				for(var i=0; i<files.length; i++ )
				{
					if(files[i].getAttachmentType() == "FILE" && files[i].getTitle().indexOf(".switch")>-1) {
						//debugger;
						//window.alert("decode email");
						//debugger;
						//console.log("Attachment URL.1: ");
						//var b = files[i].getDownloadURL();
						//debugger;
						//console.log(b);
						//console.log(b._result);
						//console.log(b);
						//debugger;

						var SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'];

						//debugger;
						//    gapi.auth.authorize(
						//      {
						//        'client_id': "939742987720-e377t00erh1q68abm9iidamcvku3sis9.apps.googleusercontent.com",
						//        'scope': SCOPES.join(' '),
						//        'immediate': true
						//      },
						//      function (authResult) {
						//        var authorizeDiv = document.getElementById('authorize-div');
						//        if (authResult && !authResult.error) {
						//        	debugger;
						//          // Hide auth UI, then load client library.
						//         authorizeDiv.style.display = 'none';
						//        loadGmailApi();
						//      } else {
						//        // Show auth UI, allowing the user to initiate authorization by
						//       // clicking authorize button.
						//       authorizeDiv.style.display = 'inline';
						//     }
						//   });

						//chrome.webRequest.onCompleted.addListener(
						//function(details) {
						//    //if (details.url.substring(0, 23) == "https://www.google.com/") // I know I do not need this
						//    {
						//        console.info("URL :" + details.url);
						//        FindData("www.altavista.com");
						//    }
						//},
						//// filters
						//{
						//    urls: [
						//        "http://*.googleusercontent.com/*",
						//        "https://*.google.com/*",
						//    ]
						//    //,types: ["image"]
						//},
						//["responseHeaders"]);
//debugger;

						$(event.messageView.getBodyElement()).find("div > div > table").replaceWith("
Decrypting message...
");

//debugger;
						var attUrl = "https://mail-attachment.googleusercontent.com/attachment/u/0/?ui=2&ik=&view=att&attid=0.1&disp=safe&th=" + event.messageView.getMessageID();
						//https://mail-attachment.googleusercontent.com/attachment/u/0/?ui=2&ik=&view=att&attid=0.1&disp=safe&th=15751a79df62f4e2
						//var attUrl = "https://mail.google.com/mail/u/0/?ui=2&ik&view=att&attid=0.1&disp=safe&th=15751a79df62f4e2&authuser=0&sadnir=1"

						files[i].getDownloadURL().then(function (e) {
							$.get({
										url: e.toString()
									})
									//.done(function() {
									//    alert( "second success" );
									//  })
									.fail(function () {
										console.log("Error loading file...");
									})
									.always(function (xmlHttp) {
										//debugger;
										console.log(xmlHttp);
										console.log("2: finished");
									});
						});
					}
				}
				//debugger;
  			}

      		console.log('View State Changed: ' + event);
    	});

	});

		// a compose view has come into existence, do something with it!
		composeView.addButton({
			title: "Encode with switch",
			iconUrl: 'http://s12.postimg.org/6da0b7cnx/Logomakr_19_MEHn.png',
			onClick: function(event) {

				//window.alert(event.composeView.getHTMLContent())

				var html = '
'+
'

	'+
'	'+
'

	'+
'
'+
'
'+
'	'+
''+
'	'+
'
This email has been sent to you securely using Egress Switch
'+
'
'+
'
'+
'

	'+
'	  '+
'
If you have Switch installed, simply open the attachment.
'+
'
Alternatively, forward this email to [[READEROPENEMAIL]] or visit Switch Web Access.
'+
'	  	'+
'
'+
'
'+
'
Regular user? Download our free desktop or mobile apps.
'+
'	'+
'
Having problems accessing the email? Click Here

'+
'	'+
'	'+
'
'+
'
'+
' '+
'
Confidentiality Notice: This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error please notify the sender.
'+
'	'+
'
'+
'
'+
' '+
'
© Copyright 2007-2011 Egress Software Technologies Ltd.
'+
' 	'+
'
';

				//var blob = new Blob([event.composeView.getHTMLContent()], {type : 'application/octet-binary', name:"encrypted.switch",fileName:"ecrypted.switch",file:"ecrypted.switch",file:"ecrypted.switch"});
				var blob = new File([event.composeView.getHTMLContent()],"encrypted.switch",{type : 'application/octet-binary'})
				event.composeView.setBodyHTML(html);
				event.composeView.attachFiles([blob]);
				//event.composeView.insertTextIntoBodyAtCursor('Hello World!');
			},
		});
		composeView.on('presending', function(event) {
			console.log("this is pre-sending event");
			//event.cancel();
		});

	});

}

);
<commit_msg>Tidied up the code a lot.<commit_after>InboxSDK.load('1', 'sdk_Hackotron-BE_a4e83dfe8a').then(function (sdk) {
        sdk.Conversations.registerMessageViewHandler(function (messageView) {
            messageView.on('load', function (event) {
                if (event.messageView.getViewState() == "EXPANDED") {
                    var files = event.messageView.getFileAttachmentCardViews();

                    for (var i = 0; i < files.length; i++) {
                        if (files[i].getAttachmentType() == "FILE" && files[i].getTitle().indexOf(".switch") > -1) {

                            var SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'];

                            $(event.messageView.getBodyElement()).find("div > div > table").
                                replaceWith("
Decrypting message...
");

                            files[i].getDownloadURL().then(function (e) {
                                $.get({
                                        url: e.toString()
                                    })
                                    .done(function (xmlHttp) {
                                        $(event.messageView.getBodyElement()).find('.egress_loadingMessage').
                                            replaceWith("
Decrypted message reads:
");

                                        $(event.messageView.getBodyElement()).find('.egress_loadingMessage').
                                            append("
" + xmlHttp + "
");

                                    })
                                    .fail(function () {
                                        console.log("Error loading file...");
                                    })
                            });
                        }
                    }
                }
            });
        });

        sdk.Compose.registerComposeViewHandler(function (composeView) {
            // a compose view has come into existence, do something with it!
            composeView.addButton({
                title: "Encode with switch",
                iconUrl: 'http://s12.postimg.org/6da0b7cnx/Logomakr_19_MEHn.png',
                onClick: function (event) {
                    var html = `

This email has been sent to you securely using Egress Switch

If you have Switch installed, simply open the attachment.

Alternatively, forward this email to [[READEROPENEMAIL]] or visit Switch Web Access.

Regular user? Download our free desktop or mobile apps.

Having problems accessing the email? Click Here

Confidentiality Notice: This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error please notify the sender.

© Copyright 2007-2011 Egress Software Technologies Ltd.

`;

                    var blob = new File([event.composeView.getHTMLContent()], "encrypted.switch", {type: 'application/octet-binary'})
                    event.composeView.setBodyHTML(html);
                    event.composeView.attachFiles([blob]);
                }
            });
            composeView.on('presending', function (event) {
                console.log("this is pre-sending event");
                //event.cancel();
            });
        });
    }
);
<|endoftext|>


<commit_before>
function parseTimesheet(appBody) {
    var d = new Date();
    var year = d.getFullYear();
    var timesheet = [];

    console.log("Getting charge numbers...");
    appBody.find("#udtColumn0").children().each(function(index, item) {
        var title = $(item).attr("title");
        if (title) {
            timesheet.push({title:title, hours:[]});
        }
    });

    console.log("Getting dates...");
    appBody.find("#hrsHeader").children().each(function(index, item) {
        for (var i = 0; i < timesheet.length; i++) {
            var dateStr = $(item).text().slice(3);
            if (dateStr.length >= 3) {
                var datePrts = dateStr.split("/");
                if (datePrts.length == 2) {
                    // Subtract one from month b/c index @ 0
                    var date = new Date(year, (parseInt(datePrts[0]) - 1), parseInt(datePrts[1]));
                    timesheet[i].hours.push({date:date, value:0});
                } else {
                    console.log("ERROR: Invalid date: ", dateStr);
                }
            }
        }
    });

    console.log("Getting hours...");
    for (var i = 0; i < timesheet.length; i++) {
        for (var j = 0; j < timesheet[i].hours.length; j++) {
            var id = "#hrs" + i + "_" + j;
            var hours = appBody.find(id).text();
            hours = parseInt(hours);
            if (isNaN(hours)) {
                hours = 0;
            }
            timesheet[i].hours[j].value = hours;
        }
    }
    return timesheet;
}

$(document).ready(function() {
    console.log("Deltrek Activated. On Deltek page.");

    $("#unitFrame").on("load", function(){
        console.log("Iframe loaded. Scanning for timesheet application...");
        appBody = $("#unitFrame").contents().find("body");

        if (appBody.find("#appTitle").text() == "Timesheet") {
            console.log("Timesheet found!");
            ts = parseTimesheet(appBody);
            console.log("Parsed: ", ts);
        } else {
            console.log("Not on timesheet page. App title: ", appBody.find("#appTitle").text());
        }
    });
});<commit_msg>Using chrome storage<commit_after>
function TimesheetDb() {
    this.month = 0;
    this.month_data = null;

    this.load = function(date) {
        var ret = null;

        chrome.storage.sync.get(date.toString(), function(item) {
            console.log("Got item: ", item);
            ret = item;
        });

        return item;
    }

    this.load_month = function(month) {

    }

    this.update = function(date_map_timesheet) {
        chrome.storage.sync.set(date_map_timesheet);
    }
}

function parseTimesheet(appBody) {
    var d = new Date();
    var year = d.getFullYear();
    var timesheet = [];

    console.log("Getting charge numbers...");
    appBody.find("#udtColumn0").children().each(function(index, item) {
        var title = $(item).attr("title");
        if (title) {
            timesheet.push({title:title, hours:[]});
        }
    });

    console.log("Getting dates...");
    appBody.find("#hrsHeader").children().each(function(index, item) {
        for (var i = 0; i < timesheet.length; i++) {
            var dateStr = $(item).text().slice(3);
            if (dateStr.length >= 3) {
                var datePrts = dateStr.split("/");
                if (datePrts.length == 2) {
                    // Subtract one from month b/c indexed at 0
                    var date = new Date(year, (parseInt(datePrts[0]) - 1), parseInt(datePrts[1]));
                    timesheet[i].hours.push({date:date, value:0});
                } else {
                    console.log("ERROR: Invalid date: ", dateStr);
                }
            }
        }
    });

    console.log("Getting hours...");
    for (var i = 0; i < timesheet.length; i++) {
        for (var j = 0; j < timesheet[i].hours.length; j++) {
            var id = "#hrs" + i + "_" + j;
            var hours = appBody.find(id).text();
            hours = parseFloat(hours);
            if (isNaN(hours)) {
                hours = 0;
            }
            timesheet[i].hours[j].value = hours;
        }
    }

    console.log("Converting so date is key...");
    date_map_timesheet = {};
    for (var i = 0; i < timesheet.length; i++) {
        var charge_str = timesheet[i].title;
        for (var j = 0; j < timesheet[i].hours.length; j++) {
            var key = timesheet[i].hours[j].date.toString();

            if (!(key in date_map_timesheet)) {
                date_map_timesheet[key] = [];
            }

            date_map_timesheet[key].push({
                title: charge_str,
                value: timesheet[i].hours[j].value
            });
        }
    }

    return date_map_timesheet;
}

$(document).ready(function() {
    console.log("Deltrek Activated. On Deltek page.");

    var db = new TimesheetDb();

    $("#unitFrame").on("load", function(){
        console.log("Iframe loaded. Scanning for timesheet application...");
        appBody = $("#unitFrame").contents().find("body");

        if (appBody.find("#appTitle").text() == "Timesheet") {
            console.log("Timesheet found!");
            ts = parseTimesheet(appBody);
            console.log("Parsed: ", ts);
            db.update(ts);
        } else {
            console.log("Not on timesheet page. App title: ", appBody.find("#appTitle").text());
        }
    });
});<|endoftext|>


<commit_before>/**
 * Dashboards' model
 */

angular.module(PKG.name+'.feature.dashboard').factory('MyDashboardsModel',
function (Widget, MyDataSource, mySettings, $q, myHelpers) {

  var dSrc = new MyDataSource(),
      API_PATH = '/configuration/dashboards';

  function Dashboard (p) {
    p = p || {};
    angular.extend(
      this,
      {
        id: p.id,
        title: p.title || 'Dashboard',
        columns: []
      }
    );

    if(angular.isArray(p.columns)) {
      angular.forEach(p.columns, function (c) {
        this.push(c.map(function (o) {
          return new Widget(o);
        }));
      }, this.columns);
    }
    else {
      // default is a single empty column
      this.columns.push([]);
    }
    this.checkForEmptyDashboard();
  }

  /**
   * rename a widget
   */
  Dashboard.prototype.renameWidget = function (widget, newName) {
    if(newName) {
      widget.title = newName;
      this.persist();
    }
  };

  /**
   * remove a widget from the active dashboard tab
   * @param  {object} w the widget object
   */
  Dashboard.prototype.removeWidget = function (widget) {
    var that = this;
    angular.forEach(that.columns, function (c, i) {
      that.columns[i] = c.filter(function (p) {
        return widget !== p;
      });
    });
    this.checkForEmptyDashboard();
    this.persist();
  };

  Dashboard.prototype.checkForEmptyDashboard = function() {
    var isEmpty = true;
    angular.forEach(this.columns, function(column) {
      if (column.length > 0) {
        isEmpty = false;
      }
    });
    this.isEmpty = isEmpty;
  };

  /**
   * add a widget to the active dashboard tab
   */
  Dashboard.prototype.addWidget = function (w) {

    function findSmallestColumn(c) {
      var index = 0,
          smallest;
      // find the column with the least widgets
      for (var i = 0; i < c.length; i++) {
        var len = c[i].length;
        if(smallest===undefined || (len < smallest)) {
          smallest = len;
          index = i;
        }
      }
      return index;
    }

    if (angular.isArray(w)) {
      angular.forEach(w, function(widget) {
        this.columns[findSmallestColumn(this.columns)].unshift(widget);
      }.bind(this));
    } else {
      w = w || new Widget({
        title: 'just added'
      });

      this.columns[findSmallestColumn(this.columns)].unshift(w);
    }
    this.persist();
  };

  /**
   * rename dashboard tab
   */
  Dashboard.prototype.rename = function (newName) {
    if(newName) {
      this.title = newName;
      this.persist();
    }
  };

  /**
   * benefit from angular's toJsonReplacer
   */
  Dashboard.prototype.properties = function () {
    return angular.fromJson(angular.toJson(this));
  };

  /**
   * save to backend
   */
  Dashboard.prototype.persist = function () {
    var body = this.properties();

    if(this.id) { // updating
      return dSrc.request(
        {
          method: 'PUT',
          _cdapNsPath: API_PATH + '/' + this.id,
          body: body
        }
      );
    }
    else { // saving
      return dSrc.request(
        {
          method: 'POST',
          _cdapNsPath: API_PATH,
          body: body
        },
        (function (result) {
          this.id = result.id;
        }).bind(this)
      );
    }
  };

/* ------------------------------------------------------------------------- */

  function Model (suffix) {
    var data = [],
        self = this,
        deferred = $q.defer();

    data.activeIndex = 0;
    this.data = data;

    this.$promise = deferred.promise;

    this._key = 'dashsbyns';
    if(suffix) { // per-namespace dashboards
      this._key += '.'+suffix;
    }

    mySettings.get(this._key, true)
      .then(function(cfg){
        if(!angular.isArray(cfg)) {
          cfg = [];
        }

        return $q.all(cfg.map(function(id){
          return dSrc.request(
            {
              method: 'GET',

              // at this point, $stateParams.namespace
              // may not be set yet... workaround
              _cdapPath: '/namespaces/' + suffix  + API_PATH + '/' + id
            }
          );
        }));
      })
      .then(function (result) {

        if(result.length) {
          // recreate saved dashboards
          angular.forEach(result, function (v) {
            var p = v.config;
            p.id = v.id;
            data.push(new Dashboard(p));
          });
        }

        deferred.resolve(self);
      }, function(err) {
        console.log("Dashboard delete failed for some reason");
        console.log(err);
        deferred.resolve(self);
      });
  }

  /**
   * direct access to the current tab's Dashboard instance
   */
  Model.prototype.current = function () {
    return this.data[this.data.activeIndex || 0];
  };

  /**
   * save dashboard config to backend
   */
  Model.prototype.persist = function () {
    return mySettings.set(this._key, this.data.map(function(one){
      return one.id;
    }));
  };

  /**
   * remove a dashboard tab
   */
  Model.prototype.remove = function (index) {
    var removed = this.data.splice(index, 1)[0];

    return dSrc.request(
      {
        method: 'DELETE',
        _cdapNsPath: API_PATH + '/' + removed.id
      }
    ).then(function() {
      return this.persist();
    }.bind(this));
  };

  /**
   * reorder dashboards
   * @param  {Boolean} reverse true to move left
   * @return {Number}         new index of current dashboard in reordered array
   */
  Model.prototype.reorder = function (reverse) {
    var max = this.data.length-1,
        index = this.data.activeIndex,
        insert = index + (reverse?-1:1);

    if(insert > max) {
      insert = 0;
    }
    else if(insert < 0) {
      insert = max;
    }

    this.data.splice(insert, 0, this.data.splice(index, 1)[0]);

    this.persist();

    return insert;
  };

  /**
   * add a new dashboard tab
   */
  Model.prototype.add = function (properties, colCount) {
    var d = new Dashboard(properties);

    // add columns as needed
    for (var i = 1; i < (colCount||3); i++) {
      d.columns.push([]);
    }

    // default widget in first column
    d.columns[0].push(new Widget({type:'welcome'}));

    this.data.push(d);

    // save to backend
    return d.persist().then((function(){
      return this.persist();
    }).bind(this));
  };

  return Model;
});
<commit_msg>remove default welcome widget<commit_after>/**
 * Dashboards' model
 */

angular.module(PKG.name+'.feature.dashboard').factory('MyDashboardsModel',
function (Widget, MyDataSource, mySettings, $q, myHelpers) {

  var dSrc = new MyDataSource(),
      API_PATH = '/configuration/dashboards';

  function Dashboard (p) {
    p = p || {};
    angular.extend(
      this,
      {
        id: p.id,
        title: p.title || 'Dashboard',
        columns: []
      }
    );

    if(angular.isArray(p.columns)) {
      angular.forEach(p.columns, function (c) {
        this.push(c.map(function (o) {
          return new Widget(o);
        }));
      }, this.columns);
    }
    else {
      // default is a single empty column
      this.columns.push([]);
    }
    this.checkForEmptyDashboard();
  }

  /**
   * rename a widget
   */
  Dashboard.prototype.renameWidget = function (widget, newName) {
    if(newName) {
      widget.title = newName;
      this.persist();
    }
  };

  /**
   * remove a widget from the active dashboard tab
   * @param  {object} w the widget object
   */
  Dashboard.prototype.removeWidget = function (widget) {
    var that = this;
    angular.forEach(that.columns, function (c, i) {
      that.columns[i] = c.filter(function (p) {
        return widget !== p;
      });
    });
    this.checkForEmptyDashboard();
    this.persist();
  };

  Dashboard.prototype.checkForEmptyDashboard = function() {
    var isEmpty = true;
    angular.forEach(this.columns, function(column) {
      if (column.length > 0) {
        isEmpty = false;
      }
    });
    this.isEmpty = isEmpty;
  };

  /**
   * add a widget to the active dashboard tab
   */
  Dashboard.prototype.addWidget = function (w) {

    function findSmallestColumn(c) {
      var index = 0,
          smallest;
      // find the column with the least widgets
      for (var i = 0; i < c.length; i++) {
        var len = c[i].length;
        if(smallest===undefined || (len < smallest)) {
          smallest = len;
          index = i;
        }
      }
      return index;
    }

    if (angular.isArray(w)) {
      angular.forEach(w, function(widget) {
        this.columns[findSmallestColumn(this.columns)].unshift(widget);
      }.bind(this));
    } else {
      w = w || new Widget({
        title: 'just added'
      });

      this.columns[findSmallestColumn(this.columns)].unshift(w);
    }
    this.persist();
  };

  /**
   * rename dashboard tab
   */
  Dashboard.prototype.rename = function (newName) {
    if(newName) {
      this.title = newName;
      this.persist();
    }
  };

  /**
   * benefit from angular's toJsonReplacer
   */
  Dashboard.prototype.properties = function () {
    return angular.fromJson(angular.toJson(this));
  };

  /**
   * save to backend
   */
  Dashboard.prototype.persist = function () {
    var body = this.properties();

    if(this.id) { // updating
      return dSrc.request(
        {
          method: 'PUT',
          _cdapNsPath: API_PATH + '/' + this.id,
          body: body
        }
      );
    }
    else { // saving
      return dSrc.request(
        {
          method: 'POST',
          _cdapNsPath: API_PATH,
          body: body
        },
        (function (result) {
          this.id = result.id;
        }).bind(this)
      );
    }
  };

/* ------------------------------------------------------------------------- */

  function Model (suffix) {
    var data = [],
        self = this,
        deferred = $q.defer();

    data.activeIndex = 0;
    this.data = data;

    this.$promise = deferred.promise;

    this._key = 'dashsbyns';
    if(suffix) { // per-namespace dashboards
      this._key += '.'+suffix;
    }

    mySettings.get(this._key, true)
      .then(function(cfg){
        if(!angular.isArray(cfg)) {
          cfg = [];
        }

        return $q.all(cfg.map(function(id){
          return dSrc.request(
            {
              method: 'GET',

              // at this point, $stateParams.namespace
              // may not be set yet... workaround
              _cdapPath: '/namespaces/' + suffix  + API_PATH + '/' + id
            }
          );
        }));
      })
      .then(function (result) {

        if(result.length) {
          // recreate saved dashboards
          angular.forEach(result, function (v) {
            var p = v.config;
            p.id = v.id;
            data.push(new Dashboard(p));
          });
        }

        deferred.resolve(self);
      }, function(err) {
        console.log("Dashboard delete failed for some reason");
        console.log(err);
        deferred.resolve(self);
      });
  }

  /**
   * direct access to the current tab's Dashboard instance
   */
  Model.prototype.current = function () {
    return this.data[this.data.activeIndex || 0];
  };

  /**
   * save dashboard config to backend
   */
  Model.prototype.persist = function () {
    return mySettings.set(this._key, this.data.map(function(one){
      return one.id;
    }));
  };

  /**
   * remove a dashboard tab
   */
  Model.prototype.remove = function (index) {
    var removed = this.data.splice(index, 1)[0];

    return dSrc.request(
      {
        method: 'DELETE',
        _cdapNsPath: API_PATH + '/' + removed.id
      }
    ).then(function() {
      return this.persist();
    }.bind(this));
  };

  /**
   * reorder dashboards
   * @param  {Boolean} reverse true to move left
   * @return {Number}         new index of current dashboard in reordered array
   */
  Model.prototype.reorder = function (reverse) {
    var max = this.data.length-1,
        index = this.data.activeIndex,
        insert = index + (reverse?-1:1);

    if(insert > max) {
      insert = 0;
    }
    else if(insert < 0) {
      insert = max;
    }

    this.data.splice(insert, 0, this.data.splice(index, 1)[0]);

    this.persist();

    return insert;
  };

  /**
   * add a new dashboard tab
   */
  Model.prototype.add = function (properties, colCount) {
    var d = new Dashboard(properties);

    // add columns as needed
    for (var i = 1; i < (colCount||3); i++) {
      d.columns.push([]);
    }

    this.data.push(d);

    // save to backend
    return d.persist().then((function(){
      return this.persist();
    }).bind(this));
  };

  return Model;
});
<|endoftext|>


<commit_before>var direction_course = '';

var reqToMP = new XMLHttpRequest;
reqToMP.open('GET', 'https://mining-profit.com/api/bitcoinprice', true);
reqToMP.onload  = buildExtencion.bind(this);
reqToMP.send(null);

var update_data = setInterval(function(){
	updateReq();
}, 60*1000);

function updateReq(){
	var reqToMP = new XMLHttpRequest;
	reqToMP.open('GET', 'https://mining-profit.com/api/bitcoinprice', true);
	reqToMP.onload  = updateExtField.bind(this);
	reqToMP.send(null);
}

function updateExtField(e){
	var dataBTC = JSON.parse(e.target.responseText);
	var curr_price =  parseFloat(dataBTC.last_price_BTCUSD);
	if(document.getElementById('mp_container_extension')){
		var prev_price = parseFloat(document.getElementById('mp_container_extension').getElementsByClassName('course-value').item(0).innerHTML);
		if(curr_price != prev_price){
			var today_open = parseFloat(dataBTC.today_open);
			var today_change = (((curr_price - today_open)/today_open)*100).toFixed(2);
			var arrow_direction = (curr_price >= today_open)?'up':'down';
			document.getElementById('mp_container_extension').getElementsByClassName('course-value').item(0).innerHTML = curr_price.toFixed(2);
			document.getElementById('mp_container_extension').getElementsByClassName('pch-value').item(0).innerHTML = today_change+'%';
			var col_right = document.getElementById('mp_container_extension').getElementsByClassName('price-detail-col-right');
			col_right.item(0).innerHTML = '$'+dataBTC.today_open;
			col_right.item(1).innerHTML = '$'+dataBTC.high;
			col_right.item(2).innerHTML = '$'+dataBTC.low;
			if(arrow_direction != direction_course){
				var arrow_box = document.getElementById('mp_container_extension').getElementsByClassName('big-change-'+direction_course).item(0);
				arrow_box.className = 'big-price-change big-change-'+arrow_direction;
				direction_course = arrow_direction;
				console.log('change direction');
			}
			console.log('success!!: direction: '+direction_course);
		}
	}
}

function buildExtencion(e){
	var dataBTC = JSON.parse(e.target.responseText);
	var curr_price =  parseFloat(dataBTC.last_price_BTCUSD);
	var today_open = parseFloat(dataBTC.today_open);
	var today_high = dataBTC.high;
	var today_low = dataBTC.low;
	var today_change = (((curr_price - today_open)/today_open)*100).toFixed(2);
	var arrow_direction = (curr_price >= today_open)?'up':'down';
	direction_course = arrow_direction;

	var mp_container = document.createElement("div");
	mp_container.setAttribute('id', 'mp_container_extension');

	var up_ext = document.createElement("div");
	up_ext.setAttribute('class', 'up-ext');

	up_ext.innerHTML = ''+
		''+
		''+
		'

';
	mp_container.appendChild(up_ext);

	var down_ext = document.createElement('div');
	down_ext.setAttribute('class', 'down-ext');

	down_ext.innerHTML = ''+
		'
'+
			'
'+
				'Bitstamp.net'+
			'
'+
			''+
			''+
		'
'+
		'
'+
			'
'+
				'
'+
					'$'+
					''+curr_price.toFixed(2)+''+
				'
'+
				'
'+
					'

'+
					'
'+today_change+'%
'+
				'
'+
			'
'+
			'
'+
				'
'+
					'
Today`s OPEN
'+
					'
$'+today_open+'
'+
				'
'+
				'
'+
					'
Today`s HIGH
'+
					'
$'+today_high+'
'+
				'
'+
				'
'+
					'
Today`s LOW
'+
					'
$'+today_low+'
'+
				'
'+
			'
'+
			'
'+
				'Powered by '+
				'Mining-Profit.com'+
			'
'+
		'
';

	mp_container.appendChild(down_ext);

	document.body.appendChild(mp_container);

	var cont_in_DOM = document.getElementById('mp_container_extension');
	document.getElementById('mp_container_ext_close_cross').onclick = function(){
		document.body.removeChild(cont_in_DOM);
		clearInterval(update_data);
	}
}<commit_msg>fix so stpd bag with link<commit_after>var direction_course = '';

var reqToMP = new XMLHttpRequest;
reqToMP.open('GET', 'https://mining-profit.com/api/bitcoinprice', true);
reqToMP.onload  = buildExtencion.bind(this);
reqToMP.send(null);

var update_data = setInterval(function(){
	updateReq();
}, 60*1000);

function updateReq(){
	var reqToMP = new XMLHttpRequest;
	reqToMP.open('GET', 'https://mining-profit.com/api/bitcoinprice', true);
	reqToMP.onload  = updateExtField.bind(this);
	reqToMP.send(null);
}

function updateExtField(e){
	var dataBTC = JSON.parse(e.target.responseText);
	var curr_price =  parseFloat(dataBTC.last_price_BTCUSD);
	if(document.getElementById('mp_container_extension')){
		var prev_price = parseFloat(document.getElementById('mp_container_extension').getElementsByClassName('course-value').item(0).innerHTML);
		if(curr_price != prev_price){
			var today_open = parseFloat(dataBTC.today_open);
			var today_change = (((curr_price - today_open)/today_open)*100).toFixed(2);
			var arrow_direction = (curr_price >= today_open)?'up':'down';
			document.getElementById('mp_container_extension').getElementsByClassName('course-value').item(0).innerHTML = curr_price.toFixed(2);
			document.getElementById('mp_container_extension').getElementsByClassName('pch-value').item(0).innerHTML = today_change+'%';
			var col_right = document.getElementById('mp_container_extension').getElementsByClassName('price-detail-col-right');
			col_right.item(0).innerHTML = '$'+dataBTC.today_open;
			col_right.item(1).innerHTML = '$'+dataBTC.high;
			col_right.item(2).innerHTML = '$'+dataBTC.low;
			if(arrow_direction != direction_course){
				var arrow_box = document.getElementById('mp_container_extension').getElementsByClassName('big-change-'+direction_course).item(0);
				arrow_box.className = 'big-price-change big-change-'+arrow_direction;
				direction_course = arrow_direction;
				console.log('change direction');
			}
			console.log('success!!: direction: '+direction_course);
		}
	}
}

function buildExtencion(e){
	var dataBTC = JSON.parse(e.target.responseText);
	var curr_price =  parseFloat(dataBTC.last_price_BTCUSD);
	var today_open = parseFloat(dataBTC.today_open);
	var today_high = dataBTC.high;
	var today_low = dataBTC.low;
	var today_change = (((curr_price - today_open)/today_open)*100).toFixed(2);
	var arrow_direction = (curr_price >= today_open)?'up':'down';
	direction_course = arrow_direction;

	var mp_container = document.createElement("div");
	mp_container.setAttribute('id', 'mp_container_extension');

	var up_ext = document.createElement("div");
	up_ext.setAttribute('class', 'up-ext');

	up_ext.innerHTML = ''+
		''+
		''+
		'

';
	mp_container.appendChild(up_ext);

	var down_ext = document.createElement('div');
	down_ext.setAttribute('class', 'down-ext');

	down_ext.innerHTML = ''+
		'
'+
			'
'+
				'Bitstamp.net'+
			'
'+
			''+
			''+
		'
'+
		'
'+
			'
'+
				'
'+
					'$'+
					''+curr_price.toFixed(2)+''+
				'
'+
				'
'+
					'

'+
					'
'+today_change+'%
'+
				'
'+
			'
'+
			'
'+
				'
'+
					'
Today`s OPEN
'+
					'
$'+today_open+'
'+
				'
'+
				'
'+
					'
Today`s HIGH
'+
					'
$'+today_high+'
'+
				'
'+
				'
'+
					'
Today`s LOW
'+
					'
$'+today_low+'
'+
				'
'+
			'
'+
			'
'+
				'Powered by '+
				'Mining-Profit.com'+
			'
'+
		'
';

	mp_container.appendChild(down_ext);

	document.body.appendChild(mp_container);

	var cont_in_DOM = document.getElementById('mp_container_extension');
	document.getElementById('mp_container_ext_close_cross').onclick = function(){
		document.body.removeChild(cont_in_DOM);
		clearInterval(update_data);
	}
}<|endoftext|>


<commit_before>var LookListenRead = (function() {

  if (!Array.prototype.last){
    Array.prototype.last = function(){
      return this[this.length - 1];
    };
  };

  var playing = false,
      position = null,
      options, voice, chunks;

  var commands = {
    next: () => goto(position+1),
    previous: () => goto(position-1),
    nextBlock: () => moveBlocks(1),
    previousBlock: () => moveBlocks(-1),
    pauseOrResume: pauseOrResume,
    slowdown: () => speedup(-10),
    speedup: () => speedup(10),
    start: start,
    exitMode: exitMode
  };

  function initVoice(callback) {
    var voices = speechSynthesis.getVoices();
    console.log("Found voices: " + voices.length);
    voice = voices.find(v => v.name == options.voice);
    if (voice) {
      callback();
    } else {
      console.log("LookListenRead: Selected voice not found. Waiting for voices...");
      speechSynthesis.onvoiceschanged = () => initVoice(callback)
    }
  }

  function speakText(text, callback) {
    var msg = new SpeechSynthesisUtterance(text);
    msg.rate = options.rate;
    msg.voice = voice;
    msg.onend = e => playing && callback();
    msg.onerror = console.log;
    speechSynthesis.speak(msg);
  }

  /* Chunk is a set of blast nodes sharing common block-style parent. Nodes in chunk are
     played and highlighted together. */
  function initChunks() {

    function displayType(elem) {
      return (elem.currentStyle || window.getComputedStyle(elem, "")).display;
    }

    function closestBlock(elem) {
      while (displayType(elem) !== 'block' && elem.parentNode) { elem = elem.parentNode }
      return elem;
    }

    document.normalize();
    $("body").blast({ delimiter: options.delimiter });
    var regexFilter = new RegExp(options.regexFilter);
    var regexIgnore = new RegExp(options.regexIgnore);
    chunks = [];
    Array.from(document.getElementsByClassName("blast"))
      .filter(span => regexFilter.test(span.innerText) && !regexIgnore.test(span.innerText))
         .forEach(span => {
           var chunk = chunks.length > 0 ? chunks.last() : null;
           var block = closestBlock(span);
           if (chunk && chunk.block === block &&
               chunk.text.length + span.innerText.length <= options.maxLength
           ) {
             chunk.nodes.push(span);
             chunk.text += ' ' + span.innerText;
           } else {
             chunks.push({nodes:[span], text:span.innerText, block: block});
           }
         });
  }

  // Position where to start new playback: selected node or the last position or first chunk
  function startPosition() {
    try {
      var selNode = getSelection().getRangeAt(0).commonAncestorContainer;
      var blastNode = selNode.nodeType == Node.TEXT_NODE ? selNode.parentNode :
                 selNode.getElementsByClassName("blast")[0];
      return chunks.findIndex(chunk => chunk.nodes.includes(blastNode));
    } catch (err) {
      return position ? position : 0;
    }
  }

  // Set new position and update highlighted chunk.
  function setPosition(pos) {
    if (pos !== null) pos = Math.max(0, Math.min(chunks.length - 1, pos));
    if (position !== null)
      chunks[position].nodes.forEach(node => $(node).removeClass("llr-active"));
    position = pos;
    if (position !== null)
      chunks[position].nodes.forEach(node => $(node).addClass("llr-active"));
  }

  function play() {
    playing = true;
    speakText(chunks[position].text, () => {
      if (position < chunks.length - 1) {
        setPosition(position+1);
        play();
      } else {
        pause();
      }
    });
  }

  function pause() {
    playing = false;
    speechSynthesis.cancel();
  }

  function pauseOrResume() {
    playing ? pause() : play();
  }

  function pauseAndResume() {
    pause();
    setTimeout(play, 30);
  }

  function start() {
    setPosition(startPosition());
    pauseAndResume();
  }

  function stop() {
    pause();
    setPosition(null);
  }

  function moveBlocks(n) {
    if (position != null) {
      var dir = Math.sign(n);
      var pos = position;
      while(n) {
        var newpos = pos + dir;
        if(newpos >= 0 && newpos < chunks.length) {
          if(chunks[newpos].block !== chunks[pos].block) n -= dir;
          pos = newpos;
        } else {
          n = 0;
        }
      }
      goto(pos);
    }
  }

  function goto(pos) {
    setPosition(pos);
    playing && pauseAndResume();
  }

  function speedup(percentage) {
    options.rate *= 1 + 0.01*percentage;
    playing && pauseAndResume();
  }

  function enterMode() {
    initChunks();
    initVoice(() => {
      Mousetrap.unbind(options.hotkeys.enterMode);
      Object.keys(commands).forEach(
        cmd => Mousetrap.bind(options.hotkeys[cmd], commands[cmd]));
      chunks.forEach((chunk, pos) =>
        chunk.nodes.forEach(node => node.ondblclick = () => goto(pos)));
      console.log("LookListenRead: started listener");
    });
  }

  function exitMode() {
    stop();
    Object.keys(commands).forEach(cmd => Mousetrap.unbind(options.hotkeys[cmd]));
    Mousetrap.bind(options.hotkeys.enterMode, enterMode);
  }

  return opts => {
    options = opts;
    Mousetrap.bind(options.hotkeys.enterMode, enterMode);
  }

})();

chrome.storage.sync.get(defaults, LookListenRead);
<commit_msg>Added blocks index and block double click events.<commit_after>var LookListenRead = (function() {

  if (!Array.prototype.last){
    Array.prototype.last = function(){
      return this[this.length - 1];
    };
  };

  var playing = false,
      chunkIx = null,
      blockIx = null,
      chunks = [],
      blocks = [],
      options, voice;

  var commands = {
    next: () => gotoChunk(chunkIx + 1),
    previous: () => gotoChunk(chunkIx - 1),
    nextBlock: () => gotoBlock(blockIx + 1),
    previousBlock: () => gotoBlock(blockIx - 1),
    pauseOrResume: pauseOrResume,
    slowdown: () => speedup(-10),
    speedup: () => speedup(10),
    start: start,
    exitMode: exitMode
  };

  function initVoice(callback) {
    var voices = speechSynthesis.getVoices();
    console.log("Found voices: " + voices.length);
    voice = voices.find(v => v.name == options.voice);
    if (voice) {
      callback();
    } else {
      console.log("LookListenRead: Selected voice not found. Waiting for voices...");
      speechSynthesis.onvoiceschanged = () => initVoice(callback)
    }
  }

  function speakText(text, callback) {
    var msg = new SpeechSynthesisUtterance(text);
    msg.rate = options.rate;
    msg.voice = voice;
    msg.onend = e => playing && callback();
    msg.onerror = console.log;
    speechSynthesis.speak(msg);
  }

  /* Chunk is a set of blast nodes sharing common block-style parent. Nodes in chunk are
     played and highlighted together. */
  function initChunks() {

    function displayType(elem) {
      return (elem.currentStyle || window.getComputedStyle(elem, "")).display;
    }

    function closestBlock(elem) {
      while (displayType(elem) !== 'block' && elem.parentNode) { elem = elem.parentNode }
      return elem;
    }

    document.normalize();
    $("body").blast({ delimiter: options.delimiter });
    var regexFilter = new RegExp(options.regexFilter);
    var regexIgnore = new RegExp(options.regexIgnore);
    Array.from(document.getElementsByClassName("blast"))
      .filter(span => regexFilter.test(span.innerText) && !regexIgnore.test(span.innerText))
         .forEach(span => {
           var chunk = chunks.length > 0 ? chunks.last() : null;
           var block = closestBlock(span);
           if (chunk && chunk.block === block &&
               chunk.text.length + span.innerText.length <= options.maxLength
           ) {
             chunk.nodes.push(span);
             chunk.text += ' ' + span.innerText;
           } else {
             chunks.push({nodes:[span], text:span.innerText, block: block});
             var i = chunks.length - 1;
             blocks.length > 0 && blocks.last().node == block ?
                     blocks.last().chunkIxs.push(i) :
                     blocks.push({node: block, chunkIxs: [i]});
           }
         });
  }

  // Position where to start new playback: selected node or the last chunkIx or first chunk
  function startPosition() {
    try {
      var selNode = getSelection().getRangeAt(0).commonAncestorContainer;
      var blastNode = selNode.nodeType == Node.TEXT_NODE ? selNode.parentNode :
                 selNode.getElementsByClassName("blast")[0];
      return chunks.findIndex(chunk => chunk.nodes.includes(blastNode));
    } catch (err) {
      return chunkIx ? chunkIx : 0;
    }
  }

  function bringToRange(i, xs) {
    return i == null ? i : Math.max(0, Math.min(xs.length - 1, i));
  }

  // Set new chunkIx and update highlighted chunk.
  function setChunkIx(i) {
    if (chunkIx !== null)
      chunks[chunkIx].nodes.forEach(node => $(node).removeClass("llr-active"));
    chunkIx = i;
    blockIx = blocks.findIndex(block => block.chunkIxs.includes(chunkIx));
    if (chunkIx !== null)
      chunks[chunkIx].nodes.forEach(node => $(node).addClass("llr-active"));
  }

  function play() {
    playing = true;
    speakText(chunks[chunkIx].text, () => {
      if (chunkIx < chunks.length - 1) {
        setChunkIx(chunkIx + 1);
        play();
      } else {
        pause();
      }
    });
  }

  function pause() {
    playing = false;
    speechSynthesis.cancel();
  }

  function pauseOrResume() {
    playing ? pause() : play();
  }

  function pauseAndResume() {
    pause();
    setTimeout(play, 30);
  }

  function start() {
    setChunkIx(startPosition());
    pauseAndResume();
  }

  function stop() {
    pause();
    setChunkIx(null);
  }

  function gotoBlock(i) {
    i = bringToRange(i, blocks);
    blockIx === i || gotoChunk(blocks[i].chunkIxs[0]);
  }

  function gotoChunk(i, startPlaying) {
    i = bringToRange(i, chunks);
    if (chunkIx !== i) {
      setChunkIx(i);
      (startPlaying || playing) && pauseAndResume();
    }
  }

  function speedup(percentage) {
    options.rate *= 1 + 0.01*percentage;
    playing && pauseAndResume();
  }

  function enterMode() {
    initChunks();
    initVoice(() => {
      Mousetrap.unbind(options.hotkeys.enterMode);
      Object.keys(commands).forEach(
        cmd => Mousetrap.bind(options.hotkeys[cmd], commands[cmd]));
      chunks.forEach((chunk, i) => chunk.nodes.forEach(node => node.ondblclick = e => {
          gotoChunk(i, true);
          e.stopPropagation();
      }));
      blocks.forEach(block => block.node.ondblclick = e => {
        gotoChunk(block.chunks[0], true);
        e.stopPropagation();
      });
      console.log("LookListenRead: started listener");
    });
  }

  function exitMode() {
    stop();
    Object.keys(commands).forEach(cmd => Mousetrap.unbind(options.hotkeys[cmd]));
    Mousetrap.bind(options.hotkeys.exitMode, exitMode);
    Mousetrap.bind(options.hotkeys.enterMode, enterMode);
  }

  return opts => {
    options = opts;
    Mousetrap.bind(options.hotkeys.enterMode, enterMode);
  }

})();

chrome.storage.sync.get(defaults, LookListenRead);
<|endoftext|>


<commit_before>dc.ui.ProjectDialog = dc.ui.Dialog.extend({

  id : 'project_dialog',

  events : {
    'click .ok'                     : 'confirm',
    'click .cancel'                 : 'close',
    'click .delete'                 : '_deleteProject',
    'click .add_collaborator'       : '_showEnterEmail',
    'click .minibutton.add'         : '_addCollaborator',
    'keypress #collaborator_email'  : '_maybeAddCollaborator',
    'click .remove'                 : '_removeCollaborator'
  },

  constructor : function(options) {
    _.bindAll(this, '_finishRender');
    this.model = options.model;
    dc.ui.Dialog.call(this, {
      mode        : 'custom',
      title       : 'Edit Project'
    });
  },

  render : function(noHide) {
    if (!noHide) $(this.el).hide();
    dc.ui.Dialog.prototype.render.call(this, {editor : true, information : this.model.statistics()});
    this.$('.custom').html(JST['organizer/project_dialog']({model : this.model}));
    this.$('#project_title').val(this.model.get('title'));
    if (!this.model.get('owner')) this.$('.minibutton.delete').text("Remove");
    if (this.model.collaborators.length) {
      this._finishRender();
    } else {
      dc.ui.spinner.show();
      this.model.collaborators.fetch({success : this._finishRender});
    }
    return this;
  },

  confirm : function() {
    var title = this.$('#project_title').val();
    if (!title) return this.error("Please specify a project title.");
    this.model.save({title : title});
    this.close();
  },

  _finishRender : function() {
    dc.ui.spinner.hide();
    if (this.model.collaborators.length) {
      var views = this.model.collaborators.map(_.bind(function(account) {
        return (new dc.ui.AccountView({model : account, kind : 'collaborator'})).render(null, {project : this.model}).el;
      }, this));
      this.$('.collaborator_list tbody').append(views);
      this.$('.collaborators').show();
    }
    $(this.el).show();
    this.center();
  },

  // If we don't own it, a request to remove the project is a request to remove
  // ourselves as a collaborator.
  _deleteProject : function() {
    var wasOpen = Projects.selected()[0] == this.model;
    if (!this.model.get('owner')) {
      Projects.remove(this.model);
      this.model.collaborators.current().destroy();
    } else {
      this.model.destroy();
    }
    this.close();
    if (wasOpen && !dc.app.searcher.flags.outstandingSearch) {
      dc.app.searcher.loadDefault({clear : true});
    }
  },

  _maybeAddCollaborator : function(e) {
    if (e.keyCode == 13) this._addCollaborator();
  },

  _addCollaborator : function() {
    var email = this.$('#collaborator_email').val();
    if (!email) return this.error('Please enter an email address.');
    this.showSpinner();
    this.model.collaborators.create({email : email}, {
      success : _.bind(function(acc, resp) {
        this.model.set({collaborator_count : this.model.get('collaborator_count') + 1});
        this.render(true);
      }, this),
      error   : _.bind(function(acc) {
        this.hideSpinner();
        this.error('No DocumentCloud account was found with that email.');
      }, this)
    });
  },

  _removeCollaborator : function(e) {
    this.showSpinner();
    var collab = this.model.collaborators.get(parseInt($(e.target).attr('data-id'), 10));
    collab.destroy({
      success : _.bind(function(){ this.model.set({collaborator_count : this.model.get('collaborator_count') - 1}); this.render(true);}, this)
    });
  },

  _showEnterEmail : function() {
    this.$('.add_collaborator').hide();
    this.$('.enter_email').show();
    this.$('#collaborator_email').focus();
  }

});
<commit_msg>fixing remove yourself from a collaborated-upon project<commit_after>dc.ui.ProjectDialog = dc.ui.Dialog.extend({

  id : 'project_dialog',

  events : {
    'click .ok'                     : 'confirm',
    'click .cancel'                 : 'close',
    'click .delete'                 : '_deleteProject',
    'click .add_collaborator'       : '_showEnterEmail',
    'click .minibutton.add'         : '_addCollaborator',
    'keypress #collaborator_email'  : '_maybeAddCollaborator',
    'click .remove'                 : '_removeCollaborator'
  },

  constructor : function(options) {
    _.bindAll(this, '_finishRender');
    this.model = options.model;
    dc.ui.Dialog.call(this, {
      mode        : 'custom',
      title       : 'Edit Project'
    });
  },

  render : function(noHide) {
    if (!noHide) $(this.el).hide();
    dc.ui.Dialog.prototype.render.call(this, {editor : true, information : this.model.statistics()});
    this.$('.custom').html(JST['organizer/project_dialog']({model : this.model}));
    this.$('#project_title').val(this.model.get('title'));
    if (!this.model.get('owner')) this.$('.minibutton.delete').text("Remove");
    if (this.model.collaborators.length) {
      this._finishRender();
    } else {
      dc.ui.spinner.show();
      this.model.collaborators.fetch({success : this._finishRender});
    }
    return this;
  },

  confirm : function() {
    var title = this.$('#project_title').val();
    if (!title) return this.error("Please specify a project title.");
    this.model.save({title : title});
    this.close();
  },

  _finishRender : function() {
    dc.ui.spinner.hide();
    if (this.model.collaborators.length) {
      var views = this.model.collaborators.map(_.bind(function(account) {
        return (new dc.ui.AccountView({model : account, kind : 'collaborator'})).render(null, {project : this.model}).el;
      }, this));
      this.$('.collaborator_list tbody').append(views);
      this.$('.collaborators').show();
    }
    $(this.el).show();
    this.center();
  },

  // If we don't own it, a request to remove the project is a request to remove
  // ourselves as a collaborator.
  _deleteProject : function() {
    var wasOpen = Projects.selected()[0] == this.model;
    if (!this.model.get('owner')) {
      Projects.remove(this.model);
      var me = Accounts.current().clone();
      me.collection = this.model.collaborators;
      me.destroy();
    } else {
      this.model.destroy();
    }
    this.close();
    if (wasOpen && !dc.app.searcher.flags.outstandingSearch) {
      dc.app.searcher.loadDefault({clear : true});
    }
  },

  _maybeAddCollaborator : function(e) {
    if (e.keyCode == 13) this._addCollaborator();
  },

  _addCollaborator : function() {
    var email = this.$('#collaborator_email').val();
    if (!email) return this.error('Please enter an email address.');
    this.showSpinner();
    this.model.collaborators.create({email : email}, {
      success : _.bind(function(acc, resp) {
        this.model.set({collaborator_count : this.model.get('collaborator_count') + 1});
        this.render(true);
      }, this),
      error   : _.bind(function(acc) {
        this.hideSpinner();
        this.error('No DocumentCloud account was found with that email.');
      }, this)
    });
  },

  _removeCollaborator : function(e) {
    this.showSpinner();
    var collab = this.model.collaborators.get(parseInt($(e.target).attr('data-id'), 10));
    collab.destroy({
      success : _.bind(function(){ this.model.set({collaborator_count : this.model.get('collaborator_count') - 1}); this.render(true);}, this)
    });
  },

  _showEnterEmail : function() {
    this.$('.add_collaborator').hide();
    this.$('.enter_email').show();
    this.$('#collaborator_email').focus();
  }

});
<|endoftext|>


<commit_before>define([
    "require",
    "dijit/_Widget",
    "dijit/_Contained",
    "dijit/_Container",
    "dojo/_base/declare",
    "dojo/_base/lang",
    "dojo/_base/array",
    "../../router",
    "../../config",
    "dijit/_TemplatedMixin",
    "dojo/json",
    "dojo/Deferred",
    "dojo/DeferredList",
    "./Content",
    "./Rounded",
    "./Toolbar",
    "dojo/text!./templates/Container.html"
], function (_require, _Widget, _Contained, _Container, declare, lang, array, router, config,
    _TemplatedMixin, JSON, Deferred, DeferredList, ContentContainer,
    RoundedContainer, ToolbarContainer, template) {
    return declare([_Widget, _Contained, _Container, _TemplatedMixin], {
        templateString: template,
        deferredList: null,

        postCreate: function () {
            // summary:
            //      Parse JSON files with predefined package configurations.
            //      Collecting routes from package files.
            try {
                var deferred = [];

                /*packages = this._getPackages(JSON.parse(toolbarPackagesJSONString));
                container = new ToolbarContainer({packages: packages});

                this.addChild(container);
                console.debug("Loaded ToolbarContainer with routes", packages);

                packages = this._getPackages(JSON.parse(roundedPackagesJSONString)),
                container = new RoundedContainer({packages: packages});

                this.addChild(container);
                console.debug("Loaded RoundedContainer with packages", packages);*/

                var packageExtractor = function (resp) {
                    var packages = [];
                    array.forEach(resp, function (respItem) {
                        packages.push(respItem[1]);
                    });
                    return packages;
                };

                var def = new Deferred();
                deferred.push(def);

                this._getPackages(config.get('contentPackages')).then(
                    lang.hitch(this, function (resp) {
                        var packages = packageExtractor(resp),
                            container = new ContentContainer({
                                packages: packages
                            });

                        container.init().then(lang.hitch(this, function () {
                            this.addChild(container);
                            def.resolve();
                        }), function (e) {
                            console.error("Could not initialize ContentContainer with packages >>",
                                packages, e);
                        });
                        console.debug("Loaded ContentContainer with packages", packages);
                    })
                );

                (new DeferredList(deferred)).then(function () {
                    router.startup();
                });

                this.inherited(arguments);
            } catch (e) {
                console.error(this.declaredClass, arguments, e);
                throw e;
            }
        },

        _getPackages: function (loadedPackages) {
            // summary:
            //      Walking thru packages array and
            //      extracting routes from every package.
            //      Collect them and return.
            // returns:
            //      Array of collected routes
            try {
                var deferredList = [];
                array.forEach(loadedPackages, lang.hitch(this, function (packageRequire) {
                    try {
                        console.debug("Prepare to processing package >>>", packageRequire);
                        var deferred = new Deferred();
                        deferredList.push(deferred);

                        require(["dojo/text!" + packageRequire + "/hcb.json"],
                            lang.hitch(this, function (resource) {
                                var pack = JSON.parse(resource);

                                if (!array.every(['route', 'modules'], function (key) {
                                    return typeof pack[key] !== 'undefined';
                                })) {
                                    throw "Widget key has not found";
                                }

                                pack['package'] = (packageRequire + '/' + (pack['main'] || 'hcb'));

                                console.debug("Require package ", pack['package']);

                                require([pack['package']], lang.hitch(this, function (Package) {
                                    try {
                                        var params = {
                                            configsOfModules: pack['modules'],
                                            packageName: packageRequire,
                                            route: pack['route']
                                        };

                                        var packageObject = new Package(params);

                                        if (!packageObject.isInstanceOf(_require('./package'))) {
                                            throw "Loaded package does not " +
                                                "compatible with type ./package";
                                        }

                                        deferred.resolve(packageObject);
                                        console.log("Package loaded successfully");
                                    } catch (e) {
                                        console.error(this.declaredClass, arguments, e);
                                        throw e;
                                    }
                                }));
                            }));

                    } catch (e) {
                        console.error(this.declaredClass, arguments, e);
                        throw e;
                    }
                }));

                return new DeferredList(deferredList);
            } catch (e) {
                console.error(this.declaredClass, arguments, e);
                throw e;
            }
        }
    });
});
<commit_msg>Changed type of plugin configuration file, was plain JSON turns to JS file.<commit_after>define([
    "require",
    "dijit/_Widget",
    "dijit/_Contained",
    "dijit/_Container",
    "dojo/_base/declare",
    "dojo/_base/lang",
    "dojo/_base/array",
    "../../router",
    "../../config",
    "dijit/_TemplatedMixin",
    "dojo/json",
    "dojo/Deferred",
    "dojo/DeferredList",
    "./Content",
    "./Rounded",
    "./Toolbar",
    "dojo/text!./templates/Container.html"
], function (_require, _Widget, _Contained, _Container, declare, lang, array, router, config,
    _TemplatedMixin, JSON, Deferred, DeferredList, ContentContainer,
    RoundedContainer, ToolbarContainer, template) {
    return declare([_Widget, _Contained, _Container, _TemplatedMixin], {
        templateString: template,
        deferredList: null,

        postCreate: function () {
            // summary:
            //      Parse JSON files with predefined package configurations.
            //      Collecting routes from package files.
            try {
                var deferred = [];

                /*packages = this._getPackages(JSON.parse(toolbarPackagesJSONString));
                container = new ToolbarContainer({packages: packages});

                this.addChild(container);
                console.debug("Loaded ToolbarContainer with routes", packages);

                packages = this._getPackages(JSON.parse(roundedPackagesJSONString)),
                container = new RoundedContainer({packages: packages});

                this.addChild(container);
                console.debug("Loaded RoundedContainer with packages", packages);*/

                var packageExtractor = function (resp) {
                    var packages = [];
                    array.forEach(resp, function (respItem) {
                        packages.push(respItem[1]);
                    });
                    return packages;
                };

                var def = new Deferred();
                deferred.push(def);

                this._getPackages(config.get('contentPackages')).then(
                    lang.hitch(this, function (resp) {
                        var packages = packageExtractor(resp),
                            container = new ContentContainer({
                                packages: packages
                            });

                        container.init().then(lang.hitch(this, function () {
                            this.addChild(container);
                            def.resolve();
                        }), function (e) {
                            console.error("Could not initialize ContentContainer with packages >>",
                                packages, e);
                        });
                        console.debug("Loaded ContentContainer with packages", packages);
                    })
                );

                (new DeferredList(deferred)).then(function () {
                    router.startup();
                });

                this.inherited(arguments);
            } catch (e) {
                console.error(this.declaredClass, arguments, e);
                throw e;
            }
        },

        _getPackages: function (loadedPackages) {
            // summary:
            //      Walking thru packages array and
            //      extracting routes from every package.
            //      Collect them and return.
            // returns:
            //      Array of collected routes
            try {
                var deferredList = [];
                array.forEach(loadedPackages, lang.hitch(this, function (packageRequire) {
                    try {
                        console.debug("Prepare to processing package >>>", packageRequire);
                        var deferred = new Deferred();
                        deferredList.push(deferred);

                        require([packageRequire + "/hcb.config"],
                            lang.hitch(this, function (pack) {

                                if (!array.every(['route', 'modules'], function (key) {
                                    return typeof pack[key] !== 'undefined';
                                })) {
                                    throw "Widget key has not found";
                                }

                                pack['package'] = (packageRequire + '/' + (pack['main'] || 'hcb'));

                                console.debug("Require package ", pack['package']);

                                require([pack['package']], lang.hitch(this, function (Package) {
                                    try {
                                        var params = {
                                            configsOfModules: pack['modules'],
                                            packageName: packageRequire,
                                            route: pack['route']
                                        };

                                        var packageObject = new Package(params);

                                        if (!packageObject.isInstanceOf(_require('./package'))) {
                                            throw "Loaded package does not " +
                                                "compatible with type ./package";
                                        }

                                        deferred.resolve(packageObject);
                                        console.log("Package loaded successfully");
                                    } catch (e) {
                                        console.error(this.declaredClass, arguments, e);
                                        throw e;
                                    }
                                }));
                            }));

                    } catch (e) {
                        console.error(this.declaredClass, arguments, e);
                        throw e;
                    }
                }));

                return new DeferredList(deferredList);
            } catch (e) {
                console.error(this.declaredClass, arguments, e);
                throw e;
            }
        }
    });
});
<|endoftext|>


<commit_before>'use strict';

var assert      = require('assert');
var wrapEmitter = require('emitter-listener');

/*
 *
 * CONSTANTS
 *
 */
var CONTEXTS_SYMBOL = 'cls@contexts';
var ERROR_SYMBOL = 'error@context';

// load polyfill if native support is unavailable
if (!process.addAsyncListener) require('async-listener');

var namespaces;

function Namespace(name) {
  this.name   = name;
  // changed in 2.7: no default context
  this.active = null;
  this._set   = [];
  this.id     = null;
}

Namespace.prototype.set = function (key, value) {
  if (!this.active) {
    throw new Error("No context available. ns.run() or ns.bind() must be called first.");
  }

  this.active[key] = value;
  return value;
};

Namespace.prototype.get = function (key) {
  if (!this.active) return undefined;

  return this.active[key];
};

Namespace.prototype.createContext = function () {
  return Object.create(this.active);
};

Namespace.prototype.run = function (fn) {
  var context = this.createContext();
  this.enter(context);
  try {
    fn(context);
    return context;
  }
  catch (exception) {
    exception[ERROR_SYMBOL] = context;
    throw exception;
  }
  finally {
    this.exit(context);
  }
};

Namespace.prototype.bind = function (fn, context) {
  if (!context) {
    if (!this.active) {
      context = Object.create(this.active);
    }
    else {
      context = this.active;
    }
  }

  var self = this;
  return function () {
    self.enter(context);
    try {
      return fn.apply(this, arguments);
    }
    catch (exception) {
      exception[ERROR_SYMBOL] = context;
      throw exception;
    }
    finally {
      self.exit(context);
    }
  };
};

Namespace.prototype.enter = function (context) {
  assert.ok(context, "context must be provided for entering");

  this._set.push(this.active);
  this.active = context;
};

Namespace.prototype.exit = function (context) {
  assert.ok(context, "context must be provided for exiting");

  // Fast path for most exits that are at the top of the stack
  if (this.active === context) {
    assert.ok(this._set.length, "can't remove top context");
    this.active = this._set.pop();
    return;
  }

  // Fast search in the stack using lastIndexOf
  var index = this._set.lastIndexOf(context);

  assert.ok(index >= 0, "context not currently entered; can't exit");
  assert.ok(index,      "can't remove top context");

  this._set.splice(index, 1);
};

Namespace.prototype.bindEmitter = function (emitter) {
  assert.ok(emitter.on && emitter.addListener && emitter.emit, "can only bind real EEs");

  var namespace  = this;
  var thisSymbol = 'context@' + this.name;

  // Capture the context active at the time the emitter is bound.
  function attach(listener) {
    if (!listener) return;
    if (!listener[CONTEXTS_SYMBOL]) listener[CONTEXTS_SYMBOL] = Object.create(null);

    listener[CONTEXTS_SYMBOL][thisSymbol] = {
      namespace : namespace,
      context   : namespace.active
    };
  }

  // At emit time, bind the listener within the correct context.
  function bind(unwrapped) {
    if (!(unwrapped && unwrapped[CONTEXTS_SYMBOL])) return unwrapped;

    var wrapped  = unwrapped;
    var contexts = unwrapped[CONTEXTS_SYMBOL];
    Object.keys(contexts).forEach(function (name) {
      var thunk = contexts[name];
      wrapped = thunk.namespace.bind(wrapped, thunk.context);
    });
    return wrapped;
  }

  wrapEmitter(emitter, attach, bind);
};

/**
 * If an error comes out of a namespace, it will have a context attached to it.
 * This function knows how to find it.
 *
 * @param {Error} exception Possibly annotated error.
 */
Namespace.prototype.fromException = function (exception) {
  return exception[ERROR_SYMBOL];
};

function get(name) {
  return namespaces[name];
}

function create(name) {
  assert.ok(name, "namespace must be given a name!");

  var namespace = new Namespace(name);
  namespace.id = process.addAsyncListener({
    create : function () { return namespace.active; },
    before : function (context, storage) { if (storage) namespace.enter(storage); },
    after  : function (context, storage) { if (storage) namespace.exit(storage); },
    error  : function (storage) { if (storage) namespace.exit(storage); }
  });

  namespaces[name] = namespace;
  return namespace;
}

function destroy(name) {
  var namespace = get(name);

  assert.ok(namespace,    "can't delete nonexistent namespace!");
  assert.ok(namespace.id, "don't assign to process.namespaces directly!");

  process.removeAsyncListener(namespace.id);
  namespaces[name] = null;
}

function reset() {
  // must unregister async listeners
  if (namespaces) {
    Object.keys(namespaces).forEach(function (name) {
      destroy(name);
    });
  }
  namespaces = process.namespaces = Object.create(null);
}
reset(); // call immediately to set up

module.exports = {
  getNamespace     : get,
  createNamespace  : create,
  destroyNamespace : destroy,
  reset            : reset
};
<commit_msg>context: only use process.namespaces global<commit_after>'use strict';

var assert      = require('assert');
var wrapEmitter = require('emitter-listener');

/*
 *
 * CONSTANTS
 *
 */
var CONTEXTS_SYMBOL = 'cls@contexts';
var ERROR_SYMBOL = 'error@context';

// load polyfill if native support is unavailable
if (!process.addAsyncListener) require('async-listener');

function Namespace(name) {
  this.name   = name;
  // changed in 2.7: no default context
  this.active = null;
  this._set   = [];
  this.id     = null;
}

Namespace.prototype.set = function (key, value) {
  if (!this.active) {
    throw new Error("No context available. ns.run() or ns.bind() must be called first.");
  }

  this.active[key] = value;
  return value;
};

Namespace.prototype.get = function (key) {
  if (!this.active) return undefined;

  return this.active[key];
};

Namespace.prototype.createContext = function () {
  return Object.create(this.active);
};

Namespace.prototype.run = function (fn) {
  var context = this.createContext();
  this.enter(context);
  try {
    fn(context);
    return context;
  }
  catch (exception) {
    exception[ERROR_SYMBOL] = context;
    throw exception;
  }
  finally {
    this.exit(context);
  }
};

Namespace.prototype.bind = function (fn, context) {
  if (!context) {
    if (!this.active) {
      context = Object.create(this.active);
    }
    else {
      context = this.active;
    }
  }

  var self = this;
  return function () {
    self.enter(context);
    try {
      return fn.apply(this, arguments);
    }
    catch (exception) {
      exception[ERROR_SYMBOL] = context;
      throw exception;
    }
    finally {
      self.exit(context);
    }
  };
};

Namespace.prototype.enter = function (context) {
  assert.ok(context, "context must be provided for entering");

  this._set.push(this.active);
  this.active = context;
};

Namespace.prototype.exit = function (context) {
  assert.ok(context, "context must be provided for exiting");

  // Fast path for most exits that are at the top of the stack
  if (this.active === context) {
    assert.ok(this._set.length, "can't remove top context");
    this.active = this._set.pop();
    return;
  }

  // Fast search in the stack using lastIndexOf
  var index = this._set.lastIndexOf(context);

  assert.ok(index >= 0, "context not currently entered; can't exit");
  assert.ok(index,      "can't remove top context");

  this._set.splice(index, 1);
};

Namespace.prototype.bindEmitter = function (emitter) {
  assert.ok(emitter.on && emitter.addListener && emitter.emit, "can only bind real EEs");

  var namespace  = this;
  var thisSymbol = 'context@' + this.name;

  // Capture the context active at the time the emitter is bound.
  function attach(listener) {
    if (!listener) return;
    if (!listener[CONTEXTS_SYMBOL]) listener[CONTEXTS_SYMBOL] = Object.create(null);

    listener[CONTEXTS_SYMBOL][thisSymbol] = {
      namespace : namespace,
      context   : namespace.active
    };
  }

  // At emit time, bind the listener within the correct context.
  function bind(unwrapped) {
    if (!(unwrapped && unwrapped[CONTEXTS_SYMBOL])) return unwrapped;

    var wrapped  = unwrapped;
    var contexts = unwrapped[CONTEXTS_SYMBOL];
    Object.keys(contexts).forEach(function (name) {
      var thunk = contexts[name];
      wrapped = thunk.namespace.bind(wrapped, thunk.context);
    });
    return wrapped;
  }

  wrapEmitter(emitter, attach, bind);
};

/**
 * If an error comes out of a namespace, it will have a context attached to it.
 * This function knows how to find it.
 *
 * @param {Error} exception Possibly annotated error.
 */
Namespace.prototype.fromException = function (exception) {
  return exception[ERROR_SYMBOL];
};

function get(name) {
  return process.namespaces[name];
}

function create(name) {
  assert.ok(name, "namespace must be given a name!");

  var namespace = new Namespace(name);
  namespace.id = process.addAsyncListener({
    create : function () { return namespace.active; },
    before : function (context, storage) { if (storage) namespace.enter(storage); },
    after  : function (context, storage) { if (storage) namespace.exit(storage); },
    error  : function (storage) { if (storage) namespace.exit(storage); }
  });

  process.namespaces[name] = namespace;
  return namespace;
}

function destroy(name) {
  var namespace = get(name);

  assert.ok(namespace,    "can't delete nonexistent namespace!");
  assert.ok(namespace.id, "don't assign to process.namespaces directly!");

  process.removeAsyncListener(namespace.id);
  process.namespaces[name] = null;
}

function reset() {
  // must unregister async listeners
  if (process.namespaces) {
    Object.keys(process.namespaces).forEach(function (name) {
      destroy(name);
    });
  }
  process.namespaces = Object.create(null);
}
if (!process.namespaces) reset(); // call immediately to set up

module.exports = {
  getNamespace     : get,
  createNamespace  : create,
  destroyNamespace : destroy,
  reset            : reset
};
<|endoftext|>


<commit_before>define({
    'zh-cn': {
        'Allowed values:'             : '允许值:',
        'Compare all with predecessor': '与所有较早的比较',
        'compare changes to:'         : '将当前版本与指定版本比较:',
        'compared to'                 : '相比于',
        'Default value:'              : '默认值:',
        'Description'                 : '描述',
        'Field'                       : '字段',
        'General'                     : '概要',
        'Generated with'              : '基于',
        'Name'                        : '名称',
        'No response values.'         : '无返回值.',
        'optional'                    : '可选',
        'Parameter'                   : '参数',
        'Permission:'                 : '权限:',
        'Response'                    : '返回',
        'Send'                        : '发送',
        'Send a Sample Request'       : '发送示例请求',
        'show up to version:'         : '显示到指定版本:',
        'Size range:'                 : '取值范围:',
        'Type'                        : '类型',
        'url'                         : '网址'
    }
});
<commit_msg>Update zh_cn.js<commit_after>define({
    'zh_cn': {
        'Allowed values:'             : '允许值:',
        'Compare all with predecessor': '与所有较早的比较',
        'compare changes to:'         : '将当前版本与指定版本比较:',
        'compared to'                 : '相比于',
        'Default value:'              : '默认值:',
        'Description'                 : '描述',
        'Field'                       : '字段',
        'General'                     : '概要',
        'Generated with'              : '基于',
        'Name'                        : '名称',
        'No response values.'         : '无返回值.',
        'optional'                    : '可选',
        'Parameter'                   : '参数',
        'Permission:'                 : '权限:',
        'Response'                    : '返回',
        'Send'                        : '发送',
        'Send a Sample Request'       : '发送示例请求',
        'show up to version:'         : '显示到指定版本:',
        'Size range:'                 : '取值范围:',
        'Type'                        : '类型',
        'url'                         : '网址'
    }
});
<|endoftext|>


<commit_before>var Bluebird = require("bluebird");
var Chalk = require("chalk");
var Cli = require("structured-cli");
var ConfigFile = require("../../lib/config");
var Sandbox = require("sandboxjs");
var SuperagentProxy = require("superagent-proxy");
var UserAuthenticator = require("../../lib/userAuthenticator");
var _ = require("lodash");

module.exports = {
  onBeforeConfigure: require("./profileOptions").onBeforeConfigure,
  onBeforeHandler: onBeforeHandler
};

function onBeforeHandler(context) {
  var args = context.args;

  return sandboxFromArguments(args).then(onProfile);

  function onProfile(profile) {
    args.profile = profile;

    // Ensure V2 access token is fresh enough

    if (!args.profile.openid) return; // V1 webtask token, nothing to do

    // If V2 access token expires in less than 5 mins, get a new one

    var validUntil = new Date(args.profile.openid.valid_until);
    var now = Date.now();
    if (validUntil - now < 5 * 60 * 1000) {
      var userAuthenticator = new UserAuthenticator({
        sandboxUrl: args.profile.url,
        authorizationServer: args.profile.openid.authorization_server,
        audience: args.profile.openid.audience,
        clientId: args.profile.openid.client_id,
        refreshToken: args.profile.openid.refresh_token
      });

      return userAuthenticator
        .login({
          container: args.profile.container,
          admin: args.profile.openid.scopes.indexOf("wt:admin") > -1,
          profileName: args.profile.name,
          requestedScopes: args.profile.openid.scope
        })
        .then(function(profile) {
          args.profile = profile;
          var config = new ConfigFile();
          config.load();
          return config
            .setProfile(profile.name, {
              url: profile.url,
              token: profile.token,
              container: profile.container,
              openid: profile.openid
            })
            .tap(function() {
              return config.save();
            });
        });
    } else {
      return; // access token still valid more than 5 mins
    }
  }
}

function sandboxFromArguments(args, options) {
  return new Bluebird(function(resolve, reject) {
    if (!options) options = {};

    if (args.token) {
      if (args.profile && !options.allowProfile)
        return reject(
          new Cli.error.invalid(
            "--profile should not be specified with custom tokens"
          )
        );
      if (args.container && args.url) {
        try {
          return resolve(
            Sandbox.init({
              onBeforeRequest,
              container: args.container,
              token: args.token,
              url: args.url
            })
          );
        } catch (e) {
          return reject(e);
        }
      }
    }

    var config = new ConfigFile();
    var profile$ = config
      .load()
      .then(loadProfile)
      .then(onProfileLoaded);

    return resolve(profile$);

    function loadProfile(profiles) {
      if (_.isEmpty(profiles)) {
        throw Cli.error.hint(
          "No webtask profiles found. To get started:\n" +
            Chalk.bold("$ wt init")
        );
      }

      return config.getProfile(args.profile);
    }

    function onBeforeRequest(request) {
      const proxy = process.env.http_proxy || process.env.HTTP_PROXY;
      const result = proxy ? SuperagentProxy(request, proxy) : request;

      return result;
    }

    function onProfileLoaded(profile) {
      if (args.container) profile.container = args.container;
      if (args.url) profile.url = args.url;
      if (args.token) profile.token = args.token;

      return profile;
    }
  });
}
<commit_msg>fixed formatting<commit_after>var Bluebird = require('bluebird');
var Chalk = require('chalk');
var Cli = require('structured-cli');
var ConfigFile = require('../../lib/config');
var Sandbox = require('sandboxjs');
var SuperagentProxy = require('superagent-proxy');
var UserAuthenticator = require('../../lib/userAuthenticator');
var _ = require('lodash');

module.exports = {
    onBeforeConfigure: require('./profileOptions').onBeforeConfigure,
    onBeforeHandler: onBeforeHandler,
};

function onBeforeHandler(context) {
    var args = context.args;

    return sandboxFromArguments(args)
        .then(onProfile);

    function onProfile(profile) {
        args.profile = profile;

        // Ensure V2 access token is fresh enough

        if (!args.profile.openid) return; // V1 webtask token, nothing to do

        // If V2 access token expires in less than 5 mins, get a new one

        var validUntil = new Date(args.profile.openid.valid_until);
        var now = Date.now();
        if ((validUntil - now) < 5 * 60 * 1000) {
            var userAuthenticator = new UserAuthenticator({
                sandboxUrl: args.profile.url,
                authorizationServer: args.profile.openid.authorization_server,
                audience: args.profile.openid.audience,
                clientId: args.profile.openid.client_id,
                refreshToken: args.profile.openid.refresh_token,
            });

            return userAuthenticator
                .login({
                    container: args.profile.container,
                    admin: args.profile.openid.scopes.indexOf('wt:admin') > -1,
                    profileName: args.profile.name,
                    requestedScopes: args.profile.openid.scope,
                })
                .then(function (profile) {
                    args.profile = profile;
                    var config = new ConfigFile();
                    config.load();
                    return config.setProfile(profile.name, {
                        url: profile.url,
                        token: profile.token,
                        container: profile.container,
                        openid: profile.openid,
                    })
                    .tap(function () {
                        return config.save();
                    });
                });
        }
        else {
            return; // access token still valid more than 5 mins
        }
    }
}

function sandboxFromArguments(args, options) {
    return new Bluebird(function (resolve, reject) {
        if (!options) options = {};

        if (args.token) {
            if (args.profile && !options.allowProfile) return reject(new Cli.error.invalid('--profile should not be specified with custom tokens'));
            if (args.container && args.url) {
                try {
                    return resolve(Sandbox.init({
                        onBeforeRequest,
                        container: args.container,
                        token: args.token,
                        url: args.url,
                    }));
                } catch (e) {
                    return reject(e);
                }
            }
        }

        var config = new ConfigFile();
        var profile$ = config.load()
            .then(loadProfile)
            .then(onProfileLoaded);

        return resolve(profile$);

        function loadProfile(profiles) {
            if (_.isEmpty(profiles)) {
                throw Cli.error.hint('No webtask profiles found. To get started:\n'
                    + Chalk.bold('$ wt init'));
            }

            return config.getProfile(args.profile);
        }

        function onBeforeRequest(request) {
            const proxy = process.env.http_proxy || process.env.HTTP_PROXY;
            const result = proxy
                ?   SuperagentProxy(request, proxy)
                :   request;

            return result;
        }

        function onProfileLoaded(profile) {
            if (args.container) profile.container = args.container;
            if (args.url) profile.url = args.url;
            if (args.token) profile.token = args.token;

            return profile;
        }
    });
}
<|endoftext|>