问:
query to keep partitions separate when physically separated
I have a table that contains order/shipment history.  A basic dummy version is:

```<code>ORDERS
order_no | order_stat | stat_date
 2       | Planned    |  01-Jan-2000
 2       | Picked     |  15-Jan-2000
 2       | Planned    |  17-Jan-2000
 2       | Planned    |  05-Feb-2000
 2       | Planned    |  31-Mar-2000
 2       | Picked     |  05-Apr-2000
 2       | Shipped    |  10-Apr-2000
</code>```

I need to figure out how long each order has been in each order status/phase.  The only problem is when I create a partition on the order_no and order_stat, I get results that make sense but are not what I am looking for.

My sql:

```<code> select
    order_no
    ,order_stat
    ,stat_date
    ,lag(stat_date, 1) over (partition by order_no order by stat_date) prev_stat_date
    ,stat_date - lag(stat_date, 1) over (partition by order_no order by stat_date) date_diff
    ,row_number() over(partition by order_no, order_stat order by stat_date) rnk
 from
    orders
</code>```

Will give me the following results:

```<code>order_no | order_stat | stat_date     | prev_stat_date  |    rnk
 2       | Planned    |  01-Jan-2000  |                 |  1
 2       | Picked     |  15-Jan-2000  |  01-Jan-2000    |  1
 2       | Planned    |  17-Jan-2000  |  15-Jan-2000    |  2
 2       | Planned    |  05-Feb-2000  |  17-Jan-2000    |  3
 2       | Planned    |  31-Mar-2000  |  05-Feb-2000    |  4
 2       | Picked     |  05-Apr-2000  |  31-Mar-2000    |  2
 2       | Shipped    |  10-Apr-2000  |  05-Apr-2000    |  1
</code>```

I would like to have results that look like this (the rnk starts over when it reverts back to a previous order stat):

```<code>order_no | order_stat | stat_date     | prev_stat_date  |    rnk
 2       | Planned    |  01-Jan-2000  |                 |  1
 2       | Picked     |  15-Jan-2000  |  01-Jan-2000    |  1
 2       | Planned    |  17-Jan-2000  |  15-Jan-2000    |  1
 2       | Planned    |  05-Feb-2000  |  17-Jan-2000    |  2
 2       | Planned    |  31-Mar-2000  |  05-Feb-2000    |  3
 2       | Picked     |  05-Apr-2000  |  31-Mar-2000    |  1
 2       | Shipped    |  10-Apr-2000  |  05-Apr-2000    |  1
</code>```

I'm trying to get a running total count of how long it has been in the status (that starts over even if the status it changes to has existed previously instead of being included in the previous partition) but I have no idea how to approach this.  Any and all insight would be greatly appreciated.

答:
Continuing @Gordon's Tabibitosan approach, once you have the groupings you can get both the order within each group and the elapsed number of days for each member of the group:

```<code>-- CTE for sample data
with orders (order_no, order_stat, stat_date) as (
            select 2, 'Planned', date '2000-01-01' from dual
  union all select 2, 'Picked',  date '2000-01-15' from dual
  union all select 2, 'Planned', date '2000-01-17' from dual
  union all select 2, 'Planned', date '2000-02-05' from dual
  union all select 2, 'Planned', date '2000-03-31' from dual
  union all select 2, 'Picked ', date '2000-04-05' from dual
  union all select 2, 'Shipped', date '2000-04-10' from dual
)
-- actual query
select order_no, order_stat, stat_date, grp,
  dense_rank() over (partition by order_no, order_stat, grp order by stat_date) as rnk,
  stat_date - min(stat_date) keep (dense_rank first order by stat_date)
                over (partition by order_no, order_stat, grp) as stat_days
from (
  select order_no, order_stat, stat_date,
    row_number() over (partition by order_no order by stat_date)
      - row_number() over (partition by order_no, order_stat order by stat_date) as grp
  from orders
)
order by order_no, stat_date;

  ORDER_NO ORDER_S STAT_DATE         GRP        RNK  STAT_DAYS
---------- ------- ---------- ---------- ---------- ----------
         2 Planned 2000-01-01          0          1          0
         2 Picked  2000-01-15          1          1          0
         2 Planned 2000-01-17          1          1          0
         2 Planned 2000-02-05          1          2         19
         2 Planned 2000-03-31          1          3         74
         2 Picked  2000-04-05          5          1          0
         2 Shipped 2000-04-10          6          1          0
</code>```

The inline view is essentially what Gordon did, except it trivially does the subtraction at that level. The outer query then gets the rank the same way, but also uses an analytic function to get the earliest date for that group, and subtracts it from the current row's date. You don't have to include grp or rnk in your final result of course, they're shown to give more insight into what's happening.

It isn't clear exactly what you want, but you can expand even further to, for instance:

```<code>with cte1 (order_no, order_stat, stat_date, grp) as (
  select order_no, order_stat, stat_date,
    row_number() over (partition by order_no order by stat_date)
      - row_number() over (partition by order_no, order_stat order by stat_date)
  from orders
),
cte2 (order_no, order_stat, stat_date, grp, grp_date, rnk) as (
  select order_no, order_stat, stat_date, grp,
    min(stat_date) keep (dense_rank first order by stat_date)
      over (partition by order_no, order_stat, grp),
    dense_rank() over (partition by order_no, order_stat, grp order by stat_date)
  from cte1
)
select order_no, order_stat, stat_date, grp, grp_date, rnk,
  stat_date - grp_date as stat_days_so_far,
  case
    when order_stat != 'Shipped' then
      coalesce(first_value(stat_date)
                 over (partition by order_no order by grp_date
                   range between 1 following and unbounded following), trunc(sysdate))
        - min(stat_date) keep (dense_rank first order by stat_date)
            over (partition by order_no, order_stat, grp)
  end as stat_days_total,
  stat_date - min(stat_date) over (partition by order_no) as order_days_so_far,
  case
    when max(order_stat) keep (dense_rank last order by stat_date)
           over (partition by order_no) = 'Shipped' then
      max(stat_date) over (partition by order_no)
    else
      trunc(sysdate)
  end
    - min(stat_date) over (partition by order_no) as order_days_total
from cte2
order by order_no, stat_date;
</code>```

which for your sample data gives:

```<code>  ORDER_NO ORDER_S STAT_DATE         GRP GRP_DATE          RNK STAT_DAYS_SO_FAR STAT_DAYS_TOTAL ORDER_DAYS_SO_FAR ORDER_DAYS_TOTAL
---------- ------- ---------- ---------- ---------- ---------- ---------------- --------------- ----------------- ----------------
         2 Planned 2000-01-01          0 2000-01-01          1                0              14                 0              100
         2 Picked  2000-01-15          1 2000-01-15          1                0               2                14              100
         2 Planned 2000-01-17          1 2000-01-17          1                0              79                16              100
         2 Planned 2000-02-05          1 2000-01-17          2               19              79                35              100
         2 Planned 2000-03-31          1 2000-01-17          3               74              79                90              100
         2 Picked  2000-04-05          5 2000-04-05          1                0               5                95              100
         2 Shipped 2000-04-10          6 2000-04-10          1                0                               100              100
</code>```

I've included some logic to assume that 'Shipped' is the final status, and if that hasn't been reached then the last status is still running - so counting up to today. That might be wrong, and you might have other end-status values (e.g. cancelled). Anyway, a few things for you to explore and play with...

You might be able to do something similar with match_recognize, but I'll leave that to someone else.

Body:
I have a table that contains order/shipment history.  A basic dummy version is:

ORDERS
order_no | order_stat | stat_date
 2       | Planned    |  01-Jan-2000
 2       | Picked     |  15-Jan-2000
 2       | Planned    |  17-Jan-2000
 2       | Planned    |  05-Feb-2000
 2       | Planned    |  31-Mar-2000
 2       | Picked     |  05-Apr-2000
 2       | Shipped    |  10-Apr-2000

I need to figure out how long each order has been in each order status/phase.  The only problem is when I create a partition on the order_no and order_stat, I get results that make sense but are not what I am looking for.

My sql:

 select
    order_no
    ,order_stat
    ,stat_date
    ,lag(stat_date, 1) over (partition by order_no order by stat_date) prev_stat_date
    ,stat_date - lag(stat_date, 1) over (partition by order_no order by stat_date) date_diff
    ,row_number() over(partition by order_no, order_stat order by stat_date) rnk
 from
    orders

Will give me the following results:

order_no | order_stat | stat_date     | prev_stat_date  |    rnk
 2       | Planned    |  01-Jan-2000  |                 |  1
 2       | Picked     |  15-Jan-2000  |  01-Jan-2000    |  1
 2       | Planned    |  17-Jan-2000  |  15-Jan-2000    |  2
 2       | Planned    |  05-Feb-2000  |  17-Jan-2000    |  3
 2       | Planned    |  31-Mar-2000  |  05-Feb-2000    |  4
 2       | Picked     |  05-Apr-2000  |  31-Mar-2000    |  2
 2       | Shipped    |  10-Apr-2000  |  05-Apr-2000    |  1

I would like to have results that look like this (the rnk starts over when it reverts back to a previous order stat):

order_no | order_stat | stat_date     | prev_stat_date  |    rnk
 2       | Planned    |  01-Jan-2000  |                 |  1
 2       | Picked     |  15-Jan-2000  |  01-Jan-2000    |  1
 2       | Planned    |  17-Jan-2000  |  15-Jan-2000    |  1
 2       | Planned    |  05-Feb-2000  |  17-Jan-2000    |  2
 2       | Planned    |  31-Mar-2000  |  05-Feb-2000    |  3
 2       | Picked     |  05-Apr-2000  |  31-Mar-2000    |  1
 2       | Shipped    |  10-Apr-2000  |  05-Apr-2000    |  1

I'm trying to get a running total count of how long it has been in the status (that starts over even if the status it changes to has existed previously instead of being included in the previous partition) but I have no idea how to approach this.  Any and all insight would be greatly appreciated.

Body:
Continuing @Gordon's Tabibitosan approach, once you have the groupings you can get both the order within each group and the elapsed number of days for each member of the group:

-- CTE for sample data
with orders (order_no, order_stat, stat_date) as (
            select 2, 'Planned', date '2000-01-01' from dual
  union all select 2, 'Picked',  date '2000-01-15' from dual
  union all select 2, 'Planned', date '2000-01-17' from dual
  union all select 2, 'Planned', date '2000-02-05' from dual
  union all select 2, 'Planned', date '2000-03-31' from dual
  union all select 2, 'Picked ', date '2000-04-05' from dual
  union all select 2, 'Shipped', date '2000-04-10' from dual
)
-- actual query
select order_no, order_stat, stat_date, grp,
  dense_rank() over (partition by order_no, order_stat, grp order by stat_date) as rnk,
  stat_date - min(stat_date) keep (dense_rank first order by stat_date)
                over (partition by order_no, order_stat, grp) as stat_days
from (
  select order_no, order_stat, stat_date,
    row_number() over (partition by order_no order by stat_date)
      - row_number() over (partition by order_no, order_stat order by stat_date) as grp
  from orders
)
order by order_no, stat_date;

  ORDER_NO ORDER_S STAT_DATE         GRP        RNK  STAT_DAYS
---------- ------- ---------- ---------- ---------- ----------
         2 Planned 2000-01-01          0          1          0
         2 Picked  2000-01-15          1          1          0
         2 Planned 2000-01-17          1          1          0
         2 Planned 2000-02-05          1          2         19
         2 Planned 2000-03-31          1          3         74
         2 Picked  2000-04-05          5          1          0
         2 Shipped 2000-04-10          6          1          0

The inline view is essentially what Gordon did, except it trivially does the subtraction at that level. The outer query then gets the rank the same way, but also uses an analytic function to get the earliest date for that group, and subtracts it from the current row's date. You don't have to include grp or rnk in your final result of course, they're shown to give more insight into what's happening.

It isn't clear exactly what you want, but you can expand even further to, for instance:

with cte1 (order_no, order_stat, stat_date, grp) as (
  select order_no, order_stat, stat_date,
    row_number() over (partition by order_no order by stat_date)
      - row_number() over (partition by order_no, order_stat order by stat_date)
  from orders
),
cte2 (order_no, order_stat, stat_date, grp, grp_date, rnk) as (
  select order_no, order_stat, stat_date, grp,
    min(stat_date) keep (dense_rank first order by stat_date)
      over (partition by order_no, order_stat, grp),
    dense_rank() over (partition by order_no, order_stat, grp order by stat_date)
  from cte1
)
select order_no, order_stat, stat_date, grp, grp_date, rnk,
  stat_date - grp_date as stat_days_so_far,
  case
    when order_stat != 'Shipped' then
      coalesce(first_value(stat_date)
                 over (partition by order_no order by grp_date
                   range between 1 following and unbounded following), trunc(sysdate))
        - min(stat_date) keep (dense_rank first order by stat_date)
            over (partition by order_no, order_stat, grp)
  end as stat_days_total,
  stat_date - min(stat_date) over (partition by order_no) as order_days_so_far,
  case
    when max(order_stat) keep (dense_rank last order by stat_date)
           over (partition by order_no) = 'Shipped' then
      max(stat_date) over (partition by order_no)
    else
      trunc(sysdate)
  end
    - min(stat_date) over (partition by order_no) as order_days_total
from cte2
order by order_no, stat_date;

which for your sample data gives:

  ORDER_NO ORDER_S STAT_DATE         GRP GRP_DATE          RNK STAT_DAYS_SO_FAR STAT_DAYS_TOTAL ORDER_DAYS_SO_FAR ORDER_DAYS_TOTAL
---------- ------- ---------- ---------- ---------- ---------- ---------------- --------------- ----------------- ----------------
         2 Planned 2000-01-01          0 2000-01-01          1                0              14                 0              100
         2 Picked  2000-01-15          1 2000-01-15          1                0               2                14              100
         2 Planned 2000-01-17          1 2000-01-17          1                0              79                16              100
         2 Planned 2000-02-05          1 2000-01-17          2               19              79                35              100
         2 Planned 2000-03-31          1 2000-01-17          3               74              79                90              100
         2 Picked  2000-04-05          5 2000-04-05          1                0               5                95              100
         2 Shipped 2000-04-10          6 2000-04-10          1                0                               100              100

I've included some logic to assume that 'Shipped' is the final status, and if that hasn't been reached then the last status is still running - so counting up to today. That might be wrong, and you might have other end-status values (e.g. cancelled). Anyway, a few things for you to explore and play with...

You might be able to do something similar with match_recognize, but I'll leave that to someone else.


来源: stackexchange

问:
Multiple scatter plots in a single figure from multiple data frame in R using ggplot?
I want to generate a figure that display all the scatter plots on this single figure using data from the two data frame (i.e., regressing column-A of Data1 against Column-A of Data2). Each plot in the figure should show R-square and p-value. I am more interested to know how I can use the fact_wrap function of ggplot while grabing data from multiple data frame.
I tried a couple of method but did not succeeded.

```<code>library(tidyverse)
Data1=data.frame(A=runif(20, min = 0, max = 100), B=runif(20, min = 0, max = 250), C=runif(20, min = 0, max = 300))
Data2=data.frame(A=runif(20, min = -10, max = 50), B=runif(20, min = -5, max = 150), C=runif(20, min = 5, max = 200))

#method-1: using plot functions
par(mfrow=c(3,1))
plot(Data1$A, Data2$A)
abline(lm(Data1$A ~ Data2$A))
plot(Data1$B, Data2$B)
abline(lm(Data1$B ~ Data2$B))
plot(Data1$C, Data2$C)
abline(lm(Data1$C ~ Data2$C))
dev.off()

#method-2: using ggplot
ggplot()+
  geom_point(aes(Data1$A,Data2$A))
</code>```

I want a Figure like the one below

答:
You can make a list of plots and then use grid.arrange() function.</p>

```<code>sc_plots = list()

sc_plots$sc1 = ggplot() + ...
sc_plots$sc2 = ggplot() + ...

grid.arrange(sc_plots$sc1, sc_plots$sc2,
 ncol = 3)
</code>```

ContentLicense: CC BY-SA 4.0

Body:
I want to generate a figure that display all the scatter plots on this single figure using data from the two data frame (i.e., regressing column-A of Data1 against Column-A of Data2). Each plot in the figure should show R-square and p-value. I am more interested to know how I can use the fact_wrap function of ggplot while grabing data from multiple data frame.
I tried a couple of method but did not succeeded.

library(tidyverse)
Data1=data.frame(A=runif(20, min = 0, max = 100), B=runif(20, min = 0, max = 250), C=runif(20, min = 0, max = 300))
Data2=data.frame(A=runif(20, min = -10, max = 50), B=runif(20, min = -5, max = 150), C=runif(20, min = 5, max = 200))

#method-1: using plot functions
par(mfrow=c(3,1))
plot(Data1$A, Data2$A)
abline(lm(Data1$A ~ Data2$A))
plot(Data1$B, Data2$B)
abline(lm(Data1$B ~ Data2$B))
plot(Data1$C, Data2$C)
abline(lm(Data1$C ~ Data2$C))
dev.off()

#method-2: using ggplot
ggplot()+
  geom_point(aes(Data1$A,Data2$A))

I want a Figure like the one below

Body:
You can make a list of plots and then use grid.arrange() function.

sc_plots = list()

sc_plots$sc1 = ggplot() + ...
sc_plots$sc2 = ggplot() + ...

grid.arrange(sc_plots$sc1, sc_plots$sc2,
 ncol = 3)


问:
How do I clone a generic List in Java?
I have an ArrayList<String> that I'd like to return a copy of.  ArrayList has a clone method which has the following signature:

```<code>public Object clone()
</code>```

After I call this method, how do I cast the returned Object back to ArrayList<String>?

答:
Why would you want to clone? Creating a new list usually makes more sense.

```<code>List<String> strs;
...
List<String> newStrs = new ArrayList<>(strs);
</code>```

Job done.

OwnerDisplayName: Bill the Lizard

Title: How do I clone a generic List in Java?

Body:
I have an ArrayList<String> that I'd like to return a copy of.  ArrayList has a clone method which has the following signature:

public Object clone()

After I call this method, how do I cast the returned Object back to ArrayList<String>?

LastEditorDisplayName: Bill the Lizard

Body:
Why would you want to clone? Creating a new list usually makes more sense.

List<String> strs;
...
List<String> newStrs = new ArrayList<>(strs);

Job done.

OwnerDisplayName: Tom Hawtin - tackline

ContentLicense: CC BY-SA 3.0


问:
Is LLBLGen similar to codesmith?
Is llblgen just like codesmith?

Is there any tool out there that will create all the CRUD plumbing for you?
And all queries on tables that you can filter by primary key (like Get a user by ID) or by foreign key (get user addresses by UserID if the address table has userID in it) etc.

DO code generators do more than the above?

答:
"Is llblgen just like codesmith?" : In many ways, yes. [Frans Bouma is active on SO, I'm sure he will have some input]

MyGeneration is a free tool that can create all of your CRUD plumbing.

Title: Is LLBLGen similar to codesmith?

OwnerDisplayName: Mitch Wheat

ContentLicense: CC BY-SA 2.5


问:
Difference of setting the font-size on the div vs h1
What is the difference between setting some properties directly on the div container vs directly on the element in it. For example font-size:

```<code><div class="the_last_of_us">
  <h5>Cookie Settings</h5>
</div>
</code>```

答:
Major different between setting the font-size on div vs h1 or h5 in the above example is, setting the font-size will not be inherited by the h5 by default, as it will pick the styles from the User Agent Stylesheet, unless you explicitly define it to inherit, for example

```<code>h5 {
  font-size: inherit;
}
</code>```

Whereas setting the font-size explicitly on the h5 will override the user agent stylesheet and set the font-size you have defined for the h5 element.

In other scenarios, it makes sense to set the properties on the Parent element, which will be inherited by a few elements. This will help you keep your selector specificity low. For example, setting color to the div can be inherited by the h1 element.

So instead of a selector with a property like

```<code>div h5 {
  color: #f00;
}
</code>```

You can use

```<code>div {
  color: #f00; /* Also applies color to any element inside
                  the div which can inherit color from the parent element */
}
</code>```

Body:
What is the difference between setting some properties directly on the div container vs directly on the element in it. For example font-size:

Cookie Settings

Body:
Major different between setting the font-size on div vs h1 or h5 in the above example is, setting the font-size will not be inherited by the h5 by default, as it will pick the styles from the User Agent Stylesheet, unless you explicitly define it to inherit, for example

h5 {
  font-size: inherit;
}

Whereas setting the font-size explicitly on the h5 will override the user agent stylesheet and set the font-size you have defined for the h5 element.

In other scenarios, it makes sense to set the properties on the Parent element, which will be inherited by a few elements. This will help you keep your selector specificity low. For example, setting color to the div can be inherited by the h1 element.

So instead of a selector with a property like

div h5 {
  color: #f00;
}

You can use

div {
  color: #f00; /* Also applies color to any element inside
                  the div which can inherit color from the parent element */
}


问:
Is there a way to calculate how far you have scrolled inside a div with overflow set to auto?
I need to find out how far I have scrolled inside a div. I can't use the window property to find this value as the window hasn't scrolled. Is there a way to accomplish this?</p>

答:
Answer:

In combination with the scroll event you can use the properties scrollTop(MDN), scrollHeight(MDN), and the computed CSS height.

```<code>let {scrollTop, scrollHeight} = e.currentTarget,
height = +getComputedStyle(e.currentTarget)["height"].slice(0,-2);
</code>```

note: we use the + operator to coerce the string returned by getComputedStyle and slice into a number. This is fine because we know exactly what we are getting (heights are always defined using px by default) and we know by slicing off px the value will always be a number. A more precise way of doing this if you're not sure of the returned value(a.e. rem) is to use a Regular Expression to remove non-numerals:

```<code>...
height = +getComputedStyle(e.currentTarget)["height"].replace(/\D/g, "");
</code>```

what are these?

scrollTop is the distance scrolled from the top of the element. It starts at 0 and increments until you hit the scroll limit.

scrollHeight is the total distance, plus the original height of the element.

height is simply the height of the element.

Why is this important?

To determine how far you've scrolled you would use scrollTop out of  (scrollHeight - height).

This is shown in the below example:

demo.addEventListener("scroll", function(e) {
let {scrollTop, scrollHeight} = e.currentTarget,
height = +getComputedStyle(e.currentTarget)["height"].slice(0,-2);

console.log("Scrolled " + parseInt(scrollTop) + " / " + parseInt(scrollHeight -  height));
});```
<pre class="snippet-code-css lang-css prettyprint-override"><code>html, body {
overflow: hidden;
}
div {
position: relative;
width: 50%;
left: calc(50% - 25%);
overflow: auto;
height: 101vh;
background: rgba(20,20,100, .3);
padding: 0px;
margin: 0px;
}</code>```

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tellus mauris, molestie eu vehicula quis, suscipit quis nisl. Fusce lorem purus, rhoncus eget dui nec, sagittis tincidunt odio. Interdum et malesuada fames ac ante ipsum primis in faucibus. Etiam eget odio vitae nulla porttitor maximus a eget neque. Pellentesque dictum mollis ligula, a consequat tellus feugiat vitae. Donec rutrum elementum odio, vitae egestas tellus volutpat nec. Proin tempor, odio quis molestie iaculis, lectus nibh volutpat turpis, luctus rutrum ex felis sit amet velit. Donec blandit cursus tortor in malesuada. Vestibulum faucibus, lectus vel accumsan molestie, ligula velit pharetra leo, ac imperdiet nibh quam quis mi.

Pellentesque ac dui augue. Fusce sit amet condimentum dui. Donec sodales urna nec nisl commodo, ac porta magna consectetur. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec tincidunt tellus nunc, at accumsan orci scelerisque sed. Suspendisse facilisis feugiat massa, quis egestas sapien tempus nec. Curabitur nunc ipsum, ultricies sit amet nibh sed, tincidunt tristique diam. Cras sit amet scelerisque leo, a blandit dolor. Cras lobortis leo nec est luctus molestie. Curabitur non arcu malesuada, tincidunt dolor quis, bibendum orci. Vestibulum lobortis tortor ac erat consequat, ut consequat ex consectetur. Maecenas finibus efficitur orci, sit amet gravida ipsum vestibulum a. Aliquam quis dictum mi. Vivamus sagittis fringilla quam, sed feugiat libero lobortis nec. Praesent suscipit nulla at mollis rutrum. Sed et lacus at quam feugiat varius vitae et lectus.

Suspendisse feugiat lacus eget risus elementum convallis. Vestibulum fringilla mi ac mollis sagittis. Suspendisse vel sem tincidunt, condimentum urna at, dignissim magna. Curabitur pulvinar lectus eu massa pharetra facilisis. Quisque est nisl, feugiat vitae pellentesque vel, hendrerit sed enim. Ut at dui eget eros rhoncus venenatis malesuada sit amet ligula. Pellentesque cursus vulputate egestas. Sed euismod sem vel felis sollicitudin faucibus. Cras aliquet viverra turpis sit amet pulvinar. Aliquam pellentesque dolor a pulvinar egestas. Curabitur in sagittis sapien. Vestibulum nec ipsum a risus porttitor rhoncus vitae id ex. Ut mollis, ligula eu sollicitudin commodo, nibh nibh bibendum mi, vel luctus tellus est eget eros.

Aenean congue diam id urna tincidunt consectetur. Nunc vel semper ligula. Sed ultrices, odio eu venenatis interdum, ligula velit volutpat nisl, et malesuada eros massa id ante. Sed malesuada non nisl quis imperdiet. Praesent porta fringilla fermentum. Integer id massa at orci mollis accumsan in et dolor. Nullam nisi lectus, dignissim a dapibus id, posuere sed ex. Praesent consequat, dui non imperdiet aliquam, magna diam rhoncus enim, id molestie mauris nunc eget ante. Morbi et laoreet sapien, tempor malesuada tellus. Pellentesque lectus leo, egestas eget faucibus vitae, dapibus non enim. Duis eu leo sit amet augue molestie laoreet eu ut ipsum. Vestibulum nulla enim, tempus id varius ut, egestas non elit.

Sed tincidunt lorem sed tellus lobortis vulputate. Aliquam vel accumsan massa, id ornare arcu. Phasellus non erat ut erat mollis placerat. Aliquam laoreet laoreet eros, in elementum ex maximus quis. Pellentesque in dui at purus efficitur mattis. Etiam consequat, nunc vel feugiat fringilla, ante enim aliquet tellus, nec dapibus dui justo eget nibh. Praesent enim leo, tincidunt a dictum et, mollis at neque.

Fusce maximus, enim sed congue tempus, lorem tellus hendrerit massa, eget eleifend augue nisi eget eros. Aliquam vehicula eu enim et interdum. Nullam sollicitudin nisl sapien, quis euismod dolor vestibulum eget. Curabitur consectetur, nulla quis scelerisque tincidunt, sem turpis sagittis lacus, at tincidunt nunc felis et velit. Quisque nec malesuada lectus. Cras a lorem fermentum, tincidunt dolor a, dictum eros. Suspendisse augue tellus, cursus et ex sit amet, cursus sodales nibh. Pellentesque quis lacus aliquam libero bibendum eleifend. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin eget justo nec velit ultrices porttitor. Aenean vel accumsan arcu, sit amet finibus eros.

Sed ut convallis tortor, non dictum odio. Cras eu dictum sem. Cras laoreet lectus quis sapien volutpat bibendum. Vivamus ut finibus magna. Nunc aliquet tincidunt blandit. Pellentesque nisl tortor, malesuada eu est sed, congue fermentum nibh. Curabitur eu tellus nibh. Mauris quis eleifend lacus, id lacinia erat. Suspendisse id purus mauris. Cras ornare neque ac nulla blandit, eget faucibus turpis dictum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum mattis faucibus massa. Ut dignissim justo eget malesuada iaculis. Integer venenatis malesuada euismod. Nulla sollicitudin justo non consequat pharetra. Donec ultrices mi at neque tincidunt, in scelerisque sem vehicula.

Integer ac consectetur enim. Nunc sed fringilla magna. Nullam fermentum nisl nec venenatis condimentum. Mauris leo metus, convallis ut sem eu, tincidunt malesuada nunc. Cras metus lacus, sagittis ut convallis non, tempor vel turpis. Sed ultricies tristique odio id cursus. Praesent auctor ac ipsum faucibus ultrices. Donec id metus a sem aliquet suscipit. Maecenas mi sem, posuere non turpis id, vehicula placerat arcu. Curabitur tincidunt viverra neque ac pharetra. Curabitur vitae massa vehicula lorem tristique tempor. Duis congue nunc id lacus suscipit, ut laoreet enim malesuada.

Ut velit tellus, rhoncus a gravida id, aliquam quis dolor. Nam elementum purus non leo porttitor tempus. Curabitur tempor feugiat magna ac tempus. Ut cursus ultricies rutrum. Duis a feugiat arcu. Nullam bibendum metus sed nulla feugiat scelerisque vitae nec sem. Mauris aliquam vestibulum dui a commodo. Cras vel molestie metus. Quisque ac arcu odio. Phasellus pretium a leo non lacinia. Mauris et odio dui. Praesent commodo lorem eu erat pulvinar tincidunt. Praesent sagittis interdum mauris, eu egestas dolor volutpat dignissim. Duis posuere, arcu nec placerat ullamcorper, lectus nunc tempor mauris, vitae congue lacus arcu at enim.

Quisque eu massa sit amet dui accumsan pulvinar. Ut fermentum lectus eros, at iaculis enim consectetur quis. Ut semper, mi in vehicula lacinia, purus mi sagittis orci, rhoncus tristique magna leo vel purus. In congue feugiat arcu consequat pretium. Vestibulum sit amet pellentesque neque, a dignissim nisl. Maecenas ac dolor id justo feugiat varius vel sed turpis. Donec quis mi id nibh condimentum dictum. Mauris dapibus justo quam, ut fermentum diam ultrices et. Cras lobortis leo et finibus congue. Integer sed dui id mi efficitur efficitur. Quisque id gravida magna. Duis pharetra cursus metus vel pellentesque. Integer at magna ante. Donec aliquam nulla sem, at rhoncus ex tincidunt aliquam. Vestibulum sit amet hendrerit diam.

Mauris imperdiet dui eget massa malesuada mollis. Integer consectetur varius justo sit amet posuere. Aenean semper est at justo pulvinar finibus. Nunc ac maximus dui, a euismod orci. Mauris congue orci in ullamcorper pellentesque. Etiam tincidunt lorem id diam maximus elementum. Etiam in erat libero. Curabitur vehicula sodales mi, quis iaculis nulla consequat nec. Sed cursus lectus sed velit commodo, eu ultricies sapien pulvinar.

Nulla rutrum lacus est, vel lacinia ipsum euismod congue. Nunc vel vehicula orci. Sed eget nibh in dolor volutpat scelerisque. Ut porta viverra est, sed sollicitudin lorem euismod id. Proin interdum, lorem in luctus gravida, justo elit laoreet ante, nec malesuada diam mi ut lacus. Nunc nisl mi, hendrerit rutrum ligula id, auctor commodo ligula. Donec ullamcorper scelerisque sapien, vel feugiat justo molestie sed. Curabitur faucibus dignissim urna. Cras at sodales ante.

In varius, odio et feugiat hendrerit, lectus mauris faucibus mauris, at vulputate quam tellus vel sem. Fusce posuere turpis sem, porta imperdiet lorem feugiat a. Morbi iaculis dui nec accumsan scelerisque. Duis elit diam, fermentum non diam pretium, molestie venenatis nisl. Suspendisse faucibus dapibus ipsum nec placerat. Nulla sed pretium enim. Cras semper iaculis lacinia. Cras id vulputate orci, quis tristique ante. Phasellus nec suscipit tortor, viverra elementum augue.

Duis sed finibus dui. Nunc molestie vestibulum egestas. Sed in nisi dapibus, vehicula sem in, mattis orci. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque ut interdum lacus, id pulvinar risus. Donec blandit non sapien vitae gravida. Interdum et malesuada fames ac ante ipsum primis in faucibus.

Sed sit amet odio ut nulla consequat consectetur quis ut ipsum. Donec mollis sed neque quis luctus. Sed malesuada hendrerit tempor. Sed interdum maximus maximus. Cras placerat vel leo non fringilla. Praesent tincidunt semper malesuada. Vestibulum at tellus massa. Nulla nec lobortis urna. Duis lobortis pharetra odio, sed mattis quam congue non. Fusce elementum nisl metus, eget ultricies ex aliquet vel. Praesent fermentum tellus imperdiet rutrum fermentum. Donec mauris sapien, convallis non condimentum id, vehicula in diam. Nunc odio nisi, vehicula eu metus eu, lobortis faucibus sapien. Integer pulvinar maximus mauris, vel commodo est fringilla rhoncus.

Nam rutrum egestas molestie. Praesent urna odio, egestas quis ante in, rhoncus fermentum nisi. Ut pulvinar diam id tortor bibendum, mattis luctus nulla vulputate. Mauris arcu augue, imperdiet quis metus non, porttitor fringilla erat. Nulla vel venenatis elit, in placerat lectus. Fusce dui ante, commodo sit amet laoreet at, luctus quis ligula. In feugiat nibh a augue sollicitudin, eget pellentesque massa maximus. Aenean a velit id est cursus aliquam nec vel leo. Vestibulum non efficitur libero, non sodales felis. Cras a mauris eu metus mattis mollis. Integer ac nibh congue, iaculis arcu et, vestibulum ex. Sed vel orci blandit, blandit leo id, viverra enim. In lobortis diam sit amet risus cursus ultricies. Aliquam molestie porttitor velit, pellentesque placerat ligula pulvinar in. Vestibulum porta, est vitae elementum ultricies, turpis dolor lacinia nunc, id facilisis ante sem vehicula justo.

Nullam interdum sagittis ligula, id fringilla quam dignissim in. Vestibulum ac massa et lectus hendrerit finibus nec a lorem. Aenean at elementum enim, eu rhoncus purus. Maecenas porttitor sapien nec tristique rhoncus. Donec tortor velit, ultricies at posuere sed, laoreet sit amet nunc. In nulla magna, imperdiet ut ipsum eu, vehicula bibendum turpis. Etiam sed magna quis lectus tristique elementum. Aliquam felis nisi, varius eget turpis nec, volutpat tincidunt lectus. Donec elit massa, dapibus id velit eget, sodales vehicula ligula. Vestibulum varius libero lacinia auctor rhoncus. Aliquam placerat urna dolor, sit amet fringilla velit vehicula at. Nam quis nisl cursus, tempor eros quis, venenatis lorem.

Quisque a lectus in velit tincidunt sollicitudin a non sem. Proin feugiat orci et semper tempor. Nulla vulputate orci eu consectetur sagittis. Morbi auctor dui sit amet eros varius volutpat. Quisque in neque elit. Integer sollicitudin felis mattis, efficitur lorem et, vulputate odio. Etiam at augue ut libero tempus dapibus vitae varius purus. Sed in ipsum a neque faucibus placerat at ut eros. Etiam euismod eros nunc, sed vulputate purus dignissim id. Quisque egestas purus turpis, sed cursus sapien porttitor eget. Aliquam placerat neque eget nisl consectetur, et lobortis dolor congue. Vivamus tellus sapien, convallis quis vehicula at, ultricies nec quam. Phasellus arcu lacus, malesuada id est accumsan, ultricies viverra massa. Ut lorem sapien, lacinia sit amet metus id, vehicula vulputate eros. Aliquam lorem sapien, semper ac vehicula sit amet, efficitur sagittis lectus. Integer vel sapien aliquet, tempor augue ut, molestie libero.

```
</div>
</div>
</p>

<hr>

<h2>Aside: How do I get percentages?</h2>

<p>You would simply modify the above formula from: </p>

``` scrollHeight - height
```

<p>To:</p>

```scrollTop / ( scrollHeight -  height) * 100
```

<hr>

<p><strong>Percentage Example:</strong></p>

<p><div class="snippet" data-lang="js" data-hide="true" data-console="true" data-babel="false">
<div class="snippet-code snippet-currently-hidden">
<pre class="snippet-code-js lang-js prettyprint-override"><code>demo.addEventListener("scroll", function(e) {
let {scrollTop, scrollHeight} = e.currentTarget,
height = +getComputedStyle(e.currentTarget)["height"].slice(0,-2);

console.log("Scrolled " + parseInt((parseInt(scrollTop) / parseInt(scrollHeight -  height)) * 100) + "% / 100% ");
});</code>```

html, body {
overflow: hidden;
}
div {
position: relative;
width: 50%;
left: calc(50% - 25%);
overflow: auto;
height: 101vh;
background: rgba(20,20,100, .3);
padding: 0px;
margin: 0px;
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div id="demo">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tellus mauris, molestie eu vehicula quis, suscipit quis nisl. Fusce lorem purus, rhoncus eget dui nec, sagittis tincidunt odio. Interdum et malesuada fames ac ante ipsum primis in faucibus. Etiam eget odio vitae nulla porttitor maximus a eget neque. Pellentesque dictum mollis ligula, a consequat tellus feugiat vitae. Donec rutrum elementum odio, vitae egestas tellus volutpat nec. Proin tempor, odio quis molestie iaculis, lectus nibh volutpat turpis, luctus rutrum ex felis sit amet velit. Donec blandit cursus tortor in malesuada. Vestibulum faucibus, lectus vel accumsan molestie, ligula velit pharetra leo, ac imperdiet nibh quam quis mi.

Pellentesque ac dui augue. Fusce sit amet condimentum dui. Donec sodales urna nec nisl commodo, ac porta magna consectetur. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec tincidunt tellus nunc, at accumsan orci scelerisque sed. Suspendisse facilisis feugiat massa, quis egestas sapien tempus nec. Curabitur nunc ipsum, ultricies sit amet nibh sed, tincidunt tristique diam. Cras sit amet scelerisque leo, a blandit dolor. Cras lobortis leo nec est luctus molestie. Curabitur non arcu malesuada, tincidunt dolor quis, bibendum orci. Vestibulum lobortis tortor ac erat consequat, ut consequat ex consectetur. Maecenas finibus efficitur orci, sit amet gravida ipsum vestibulum a. Aliquam quis dictum mi. Vivamus sagittis fringilla quam, sed feugiat libero lobortis nec. Praesent suscipit nulla at mollis rutrum. Sed et lacus at quam feugiat varius vitae et lectus.

Suspendisse feugiat lacus eget risus elementum convallis. Vestibulum fringilla mi ac mollis sagittis. Suspendisse vel sem tincidunt, condimentum urna at, dignissim magna. Curabitur pulvinar lectus eu massa pharetra facilisis. Quisque est nisl, feugiat vitae pellentesque vel, hendrerit sed enim. Ut at dui eget eros rhoncus venenatis malesuada sit amet ligula. Pellentesque cursus vulputate egestas. Sed euismod sem vel felis sollicitudin faucibus. Cras aliquet viverra turpis sit amet pulvinar. Aliquam pellentesque dolor a pulvinar egestas. Curabitur in sagittis sapien. Vestibulum nec ipsum a risus porttitor rhoncus vitae id ex. Ut mollis, ligula eu sollicitudin commodo, nibh nibh bibendum mi, vel luctus tellus est eget eros.

Aenean congue diam id urna tincidunt consectetur. Nunc vel semper ligula. Sed ultrices, odio eu venenatis interdum, ligula velit volutpat nisl, et malesuada eros massa id ante. Sed malesuada non nisl quis imperdiet. Praesent porta fringilla fermentum. Integer id massa at orci mollis accumsan in et dolor. Nullam nisi lectus, dignissim a dapibus id, posuere sed ex. Praesent consequat, dui non imperdiet aliquam, magna diam rhoncus enim, id molestie mauris nunc eget ante. Morbi et laoreet sapien, tempor malesuada tellus. Pellentesque lectus leo, egestas eget faucibus vitae, dapibus non enim. Duis eu leo sit amet augue molestie laoreet eu ut ipsum. Vestibulum nulla enim, tempus id varius ut, egestas non elit.

Sed tincidunt lorem sed tellus lobortis vulputate. Aliquam vel accumsan massa, id ornare arcu. Phasellus non erat ut erat mollis placerat. Aliquam laoreet laoreet eros, in elementum ex maximus quis. Pellentesque in dui at purus efficitur mattis. Etiam consequat, nunc vel feugiat fringilla, ante enim aliquet tellus, nec dapibus dui justo eget nibh. Praesent enim leo, tincidunt a dictum et, mollis at neque.

Fusce maximus, enim sed congue tempus, lorem tellus hendrerit massa, eget eleifend augue nisi eget eros. Aliquam vehicula eu enim et interdum. Nullam sollicitudin nisl sapien, quis euismod dolor vestibulum eget. Curabitur consectetur, nulla quis scelerisque tincidunt, sem turpis sagittis lacus, at tincidunt nunc felis et velit. Quisque nec malesuada lectus. Cras a lorem fermentum, tincidunt dolor a, dictum eros. Suspendisse augue tellus, cursus et ex sit amet, cursus sodales nibh. Pellentesque quis lacus aliquam libero bibendum eleifend. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin eget justo nec velit ultrices porttitor. Aenean vel accumsan arcu, sit amet finibus eros.

Sed ut convallis tortor, non dictum odio. Cras eu dictum sem. Cras laoreet lectus quis sapien volutpat bibendum. Vivamus ut finibus magna. Nunc aliquet tincidunt blandit. Pellentesque nisl tortor, malesuada eu est sed, congue fermentum nibh. Curabitur eu tellus nibh. Mauris quis eleifend lacus, id lacinia erat. Suspendisse id purus mauris. Cras ornare neque ac nulla blandit, eget faucibus turpis dictum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum mattis faucibus massa. Ut dignissim justo eget malesuada iaculis. Integer venenatis malesuada euismod. Nulla sollicitudin justo non consequat pharetra. Donec ultrices mi at neque tincidunt, in scelerisque sem vehicula.

Integer ac consectetur enim. Nunc sed fringilla magna. Nullam fermentum nisl nec venenatis condimentum. Mauris leo metus, convallis ut sem eu, tincidunt malesuada nunc. Cras metus lacus, sagittis ut convallis non, tempor vel turpis. Sed ultricies tristique odio id cursus. Praesent auctor ac ipsum faucibus ultrices. Donec id metus a sem aliquet suscipit. Maecenas mi sem, posuere non turpis id, vehicula placerat arcu. Curabitur tincidunt viverra neque ac pharetra. Curabitur vitae massa vehicula lorem tristique tempor. Duis congue nunc id lacus suscipit, ut laoreet enim malesuada.

Ut velit tellus, rhoncus a gravida id, aliquam quis dolor. Nam elementum purus non leo porttitor tempus. Curabitur tempor feugiat magna ac tempus. Ut cursus ultricies rutrum. Duis a feugiat arcu. Nullam bibendum metus sed nulla feugiat scelerisque vitae nec sem. Mauris aliquam vestibulum dui a commodo. Cras vel molestie metus. Quisque ac arcu odio. Phasellus pretium a leo non lacinia. Mauris et odio dui. Praesent commodo lorem eu erat pulvinar tincidunt. Praesent sagittis interdum mauris, eu egestas dolor volutpat dignissim. Duis posuere, arcu nec placerat ullamcorper, lectus nunc tempor mauris, vitae congue lacus arcu at enim.

Quisque eu massa sit amet dui accumsan pulvinar. Ut fermentum lectus eros, at iaculis enim consectetur quis. Ut semper, mi in vehicula lacinia, purus mi sagittis orci, rhoncus tristique magna leo vel purus. In congue feugiat arcu consequat pretium. Vestibulum sit amet pellentesque neque, a dignissim nisl. Maecenas ac dolor id justo feugiat varius vel sed turpis. Donec quis mi id nibh condimentum dictum. Mauris dapibus justo quam, ut fermentum diam ultrices et. Cras lobortis leo et finibus congue. Integer sed dui id mi efficitur efficitur. Quisque id gravida magna. Duis pharetra cursus metus vel pellentesque. Integer at magna ante. Donec aliquam nulla sem, at rhoncus ex tincidunt aliquam. Vestibulum sit amet hendrerit diam.

Mauris imperdiet dui eget massa malesuada mollis. Integer consectetur varius justo sit amet posuere. Aenean semper est at justo pulvinar finibus. Nunc ac maximus dui, a euismod orci. Mauris congue orci in ullamcorper pellentesque. Etiam tincidunt lorem id diam maximus elementum. Etiam in erat libero. Curabitur vehicula sodales mi, quis iaculis nulla consequat nec. Sed cursus lectus sed velit commodo, eu ultricies sapien pulvinar.

Nulla rutrum lacus est, vel lacinia ipsum euismod congue. Nunc vel vehicula orci. Sed eget nibh in dolor volutpat scelerisque. Ut porta viverra est, sed sollicitudin lorem euismod id. Proin interdum, lorem in luctus gravida, justo elit laoreet ante, nec malesuada diam mi ut lacus. Nunc nisl mi, hendrerit rutrum ligula id, auctor commodo ligula. Donec ullamcorper scelerisque sapien, vel feugiat justo molestie sed. Curabitur faucibus dignissim urna. Cras at sodales ante.

In varius, odio et feugiat hendrerit, lectus mauris faucibus mauris, at vulputate quam tellus vel sem. Fusce posuere turpis sem, porta imperdiet lorem feugiat a. Morbi iaculis dui nec accumsan scelerisque. Duis elit diam, fermentum non diam pretium, molestie venenatis nisl. Suspendisse faucibus dapibus ipsum nec placerat. Nulla sed pretium enim. Cras semper iaculis lacinia. Cras id vulputate orci, quis tristique ante. Phasellus nec suscipit tortor, viverra elementum augue.

Duis sed finibus dui. Nunc molestie vestibulum egestas. Sed in nisi dapibus, vehicula sem in, mattis orci. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque ut interdum lacus, id pulvinar risus. Donec blandit non sapien vitae gravida. Interdum et malesuada fames ac ante ipsum primis in faucibus.

Sed sit amet odio ut nulla consequat consectetur quis ut ipsum. Donec mollis sed neque quis luctus. Sed malesuada hendrerit tempor. Sed interdum maximus maximus. Cras placerat vel leo non fringilla. Praesent tincidunt semper malesuada. Vestibulum at tellus massa. Nulla nec lobortis urna. Duis lobortis pharetra odio, sed mattis quam congue non. Fusce elementum nisl metus, eget ultricies ex aliquet vel. Praesent fermentum tellus imperdiet rutrum fermentum. Donec mauris sapien, convallis non condimentum id, vehicula in diam. Nunc odio nisi, vehicula eu metus eu, lobortis faucibus sapien. Integer pulvinar maximus mauris, vel commodo est fringilla rhoncus.

Nam rutrum egestas molestie. Praesent urna odio, egestas quis ante in, rhoncus fermentum nisi. Ut pulvinar diam id tortor bibendum, mattis luctus nulla vulputate. Mauris arcu augue, imperdiet quis metus non, porttitor fringilla erat. Nulla vel venenatis elit, in placerat lectus. Fusce dui ante, commodo sit amet laoreet at, luctus quis ligula. In feugiat nibh a augue sollicitudin, eget pellentesque massa maximus. Aenean a velit id est cursus aliquam nec vel leo. Vestibulum non efficitur libero, non sodales felis. Cras a mauris eu metus mattis mollis. Integer ac nibh congue, iaculis arcu et, vestibulum ex. Sed vel orci blandit, blandit leo id, viverra enim. In lobortis diam sit amet risus cursus ultricies. Aliquam molestie porttitor velit, pellentesque placerat ligula pulvinar in. Vestibulum porta, est vitae elementum ultricies, turpis dolor lacinia nunc, id facilisis ante sem vehicula justo.

Nullam interdum sagittis ligula, id fringilla quam dignissim in. Vestibulum ac massa et lectus hendrerit finibus nec a lorem. Aenean at elementum enim, eu rhoncus purus. Maecenas porttitor sapien nec tristique rhoncus. Donec tortor velit, ultricies at posuere sed, laoreet sit amet nunc. In nulla magna, imperdiet ut ipsum eu, vehicula bibendum turpis. Etiam sed magna quis lectus tristique elementum. Aliquam felis nisi, varius eget turpis nec, volutpat tincidunt lectus. Donec elit massa, dapibus id velit eget, sodales vehicula ligula. Vestibulum varius libero lacinia auctor rhoncus. Aliquam placerat urna dolor, sit amet fringilla velit vehicula at. Nam quis nisl cursus, tempor eros quis, venenatis lorem.

Quisque a lectus in velit tincidunt sollicitudin a non sem. Proin feugiat orci et semper tempor. Nulla vulputate orci eu consectetur sagittis. Morbi auctor dui sit amet eros varius volutpat. Quisque in neque elit. Integer sollicitudin felis mattis, efficitur lorem et, vulputate odio. Etiam at augue ut libero tempus dapibus vitae varius purus. Sed in ipsum a neque faucibus placerat at ut eros. Etiam euismod eros nunc, sed vulputate purus dignissim id. Quisque egestas purus turpis, sed cursus sapien porttitor eget. Aliquam placerat neque eget nisl consectetur, et lobortis dolor congue. Vivamus tellus sapien, convallis quis vehicula at, ultricies nec quam. Phasellus arcu lacus, malesuada id est accumsan, ultricies viverra massa. Ut lorem sapien, lacinia sit amet metus id, vehicula vulputate eros. Aliquam lorem sapien, semper ac vehicula sit amet, efficitur sagittis lectus. Integer vel sapien aliquet, tempor augue ut, molestie libero.

</div></code>```

Body:
Answer:

In combination with the scroll event you can use the properties scrollTop(MDN), scrollHeight(MDN), and the computed CSS height.

let {scrollTop, scrollHeight} = e.currentTarget,
height = +getComputedStyle(e.currentTarget)["height"].slice(0,-2);

note: we use the + operator to coerce the string returned by getComputedStyle and slice into a number. This is fine because we know exactly what we are getting (heights are always defined using px by default) and we know by slicing off px the value will always be a number. A more precise way of doing this if you're not sure of the returned value(a.e. rem) is to use a Regular Expression to remove non-numerals:

...
height = +getComputedStyle(e.currentTarget)["height"].replace(/\D/g, "");

what are these?

scrollTop is the distance scrolled from the top of the element. It starts at 0 and increments until you hit the scroll limit.

scrollHeight is the total distance, plus the original height of the element.

height is simply the height of the element.

Why is this important?

To determine how far you've scrolled you would use scrollTop out of  (scrollHeight - height).

This is shown in the below example:

demo.addEventListener("scroll", function(e) {
let {scrollTop, scrollHeight} = e.currentTarget,
height = +getComputedStyle(e.currentTarget)["height"].slice(0,-2);

console.log("Scrolled " + parseInt(scrollTop) + " / " + parseInt(scrollHeight -  height));
});

html, body {
overflow: hidden;
}
div {
position: relative;
width: 50%;
left: calc(50% - 25%);
overflow: auto;
height: 101vh;
background: rgba(20,20,100, .3);
padding: 0px;
margin: 0px;
}

<div id="demo">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tellus mauris, molestie eu vehicula quis, suscipit quis nisl. Fusce lorem purus, rhoncus eget dui nec, sagittis tincidunt odio. Interdum et malesuada fames ac ante ipsum primis in faucibus. Etiam eget odio vitae nulla porttitor maximus a eget neque. Pellentesque dictum mollis ligula, a consequat tellus feugiat vitae. Donec rutrum elementum odio, vitae egestas tellus volutpat nec. Proin tempor, odio quis molestie iaculis, lectus nibh volutpat turpis, luctus rutrum ex felis sit amet velit. Donec blandit cursus tortor in malesuada. Vestibulum faucibus, lectus vel accumsan molestie, ligula velit pharetra leo, ac imperdiet nibh quam quis mi.

Pellentesque ac dui augue. Fusce sit amet condimentum dui. Donec sodales urna nec nisl commodo, ac porta magna consectetur. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec tincidunt tellus nunc, at accumsan orci scelerisque sed. Suspendisse facilisis feugiat massa, quis egestas sapien tempus nec. Curabitur nunc ipsum, ultricies sit amet nibh sed, tincidunt tristique diam. Cras sit amet scelerisque leo, a blandit dolor. Cras lobortis leo nec est luctus molestie. Curabitur non arcu malesuada, tincidunt dolor quis, bibendum orci. Vestibulum lobortis tortor ac erat consequat, ut consequat ex consectetur. Maecenas finibus efficitur orci, sit amet gravida ipsum vestibulum a. Aliquam quis dictum mi. Vivamus sagittis fringilla quam, sed feugiat libero lobortis nec. Praesent suscipit nulla at mollis rutrum. Sed et lacus at quam feugiat varius vitae et lectus.

Suspendisse feugiat lacus eget risus elementum convallis. Vestibulum fringilla mi ac mollis sagittis. Suspendisse vel sem tincidunt, condimentum urna at, dignissim magna. Curabitur pulvinar lectus eu massa pharetra facilisis. Quisque est nisl, feugiat vitae pellentesque vel, hendrerit sed enim. Ut at dui eget eros rhoncus venenatis malesuada sit amet ligula. Pellentesque cursus vulputate egestas. Sed euismod sem vel felis sollicitudin faucibus. Cras aliquet viverra turpis sit amet pulvinar. Aliquam pellentesque dolor a pulvinar egestas. Curabitur in sagittis sapien. Vestibulum nec ipsum a risus porttitor rhoncus vitae id ex. Ut mollis, ligula eu sollicitudin commodo, nibh nibh bibendum mi, vel luctus tellus est eget eros.

Aenean congue diam id urna tincidunt consectetur. Nunc vel semper ligula. Sed ultrices, odio eu venenatis interdum, ligula velit volutpat nisl, et malesuada eros massa id ante. Sed malesuada non nisl quis imperdiet. Praesent porta fringilla fermentum. Integer id massa at orci mollis accumsan in et dolor. Nullam nisi lectus, dignissim a dapibus id, posuere sed ex. Praesent consequat, dui non imperdiet aliquam, magna diam rhoncus enim, id molestie mauris nunc eget ante. Morbi et laoreet sapien, tempor malesuada tellus. Pellentesque lectus leo, egestas eget faucibus vitae, dapibus non enim. Duis eu leo sit amet augue molestie laoreet eu ut ipsum. Vestibulum nulla enim, tempus id varius ut, egestas non elit.

Sed tincidunt lorem sed tellus lobortis vulputate. Aliquam vel accumsan massa, id ornare arcu. Phasellus non erat ut erat mollis placerat. Aliquam laoreet laoreet eros, in elementum ex maximus quis. Pellentesque in dui at purus efficitur mattis. Etiam consequat, nunc vel feugiat fringilla, ante enim aliquet tellus, nec dapibus dui justo eget nibh. Praesent enim leo, tincidunt a dictum et, mollis at neque.

Fusce maximus, enim sed congue tempus, lorem tellus hendrerit massa, eget eleifend augue nisi eget eros. Aliquam vehicula eu enim et interdum. Nullam sollicitudin nisl sapien, quis euismod dolor vestibulum eget. Curabitur consectetur, nulla quis scelerisque tincidunt, sem turpis sagittis lacus, at tincidunt nunc felis et velit. Quisque nec malesuada lectus. Cras a lorem fermentum, tincidunt dolor a, dictum eros. Suspendisse augue tellus, cursus et ex sit amet, cursus sodales nibh. Pellentesque quis lacus aliquam libero bibendum eleifend. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin eget justo nec velit ultrices porttitor. Aenean vel accumsan arcu, sit amet finibus eros.

Sed ut convallis tortor, non dictum odio. Cras eu dictum sem. Cras laoreet lectus quis sapien volutpat bibendum. Vivamus ut finibus magna. Nunc aliquet tincidunt blandit. Pellentesque nisl tortor, malesuada eu est sed, congue fermentum nibh. Curabitur eu tellus nibh. Mauris quis eleifend lacus, id lacinia erat. Suspendisse id purus mauris. Cras ornare neque ac nulla blandit, eget faucibus turpis dictum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum mattis faucibus massa. Ut dignissim justo eget malesuada iaculis. Integer venenatis malesuada euismod. Nulla sollicitudin justo non consequat pharetra. Donec ultrices mi at neque tincidunt, in scelerisque sem vehicula.

Integer ac consectetur enim. Nunc sed fringilla magna. Nullam fermentum nisl nec venenatis condimentum. Mauris leo metus, convallis ut sem eu, tincidunt malesuada nunc. Cras metus lacus, sagittis ut convallis non, tempor vel turpis. Sed ultricies tristique odio id cursus. Praesent auctor ac ipsum faucibus ultrices. Donec id metus a sem aliquet suscipit. Maecenas mi sem, posuere non turpis id, vehicula placerat arcu. Curabitur tincidunt viverra neque ac pharetra. Curabitur vitae massa vehicula lorem tristique tempor. Duis congue nunc id lacus suscipit, ut laoreet enim malesuada.

Ut velit tellus, rhoncus a gravida id, aliquam quis dolor. Nam elementum purus non leo porttitor tempus. Curabitur tempor feugiat magna ac tempus. Ut cursus ultricies rutrum. Duis a feugiat arcu. Nullam bibendum metus sed nulla feugiat scelerisque vitae nec sem. Mauris aliquam vestibulum dui a commodo. Cras vel molestie metus. Quisque ac arcu odio. Phasellus pretium a leo non lacinia. Mauris et odio dui. Praesent commodo lorem eu erat pulvinar tincidunt. Praesent sagittis interdum mauris, eu egestas dolor volutpat dignissim. Duis posuere, arcu nec placerat ullamcorper, lectus nunc tempor mauris, vitae congue lacus arcu at enim.

Quisque eu massa sit amet dui accumsan pulvinar. Ut fermentum lectus eros, at iaculis enim consectetur quis. Ut semper, mi in vehicula lacinia, purus mi sagittis orci, rhoncus tristique magna leo vel purus. In congue feugiat arcu consequat pretium. Vestibulum sit amet pellentesque neque, a dignissim nisl. Maecenas ac dolor id justo feugiat varius vel sed turpis. Donec quis mi id nibh condimentum dictum. Mauris dapibus justo quam, ut fermentum diam ultrices et. Cras lobortis leo et finibus congue. Integer sed dui id mi efficitur efficitur. Quisque id gravida magna. Duis pharetra cursus metus vel pellentesque. Integer at magna ante. Donec aliquam nulla sem, at rhoncus ex tincidunt aliquam. Vestibulum sit amet hendrerit diam.

Mauris imperdiet dui eget massa malesuada mollis. Integer consectetur varius justo sit amet posuere. Aenean semper est at justo pulvinar finibus. Nunc ac maximus dui, a euismod orci. Mauris congue orci in ullamcorper pellentesque. Etiam tincidunt lorem id diam maximus elementum. Etiam in erat libero. Curabitur vehicula sodales mi, quis iaculis nulla consequat nec. Sed cursus lectus sed velit commodo, eu ultricies sapien pulvinar.

Nulla rutrum lacus est, vel lacinia ipsum euismod congue. Nunc vel vehicula orci. Sed eget nibh in dolor volutpat scelerisque. Ut porta viverra est, sed sollicitudin lorem euismod id. Proin interdum, lorem in luctus gravida, justo elit laoreet ante, nec malesuada diam mi ut lacus. Nunc nisl mi, hendrerit rutrum ligula id, auctor commodo ligula. Donec ullamcorper scelerisque sapien, vel feugiat justo molestie sed. Curabitur faucibus dignissim urna. Cras at sodales ante.

In varius, odio et feugiat hendrerit, lectus mauris faucibus mauris, at vulputate quam tellus vel sem. Fusce posuere turpis sem, porta imperdiet lorem feugiat a. Morbi iaculis dui nec accumsan scelerisque. Duis elit diam, fermentum non diam pretium, molestie venenatis nisl. Suspendisse faucibus dapibus ipsum nec placerat. Nulla sed pretium enim. Cras semper iaculis lacinia. Cras id vulputate orci, quis tristique ante. Phasellus nec suscipit tortor, viverra elementum augue.

Duis sed finibus dui. Nunc molestie vestibulum egestas. Sed in nisi dapibus, vehicula sem in, mattis orci. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque ut interdum lacus, id pulvinar risus. Donec blandit non sapien vitae gravida. Interdum et malesuada fames ac ante ipsum primis in faucibus.

Sed sit amet odio ut nulla consequat consectetur quis ut ipsum. Donec mollis sed neque quis luctus. Sed malesuada hendrerit tempor. Sed interdum maximus maximus. Cras placerat vel leo non fringilla. Praesent tincidunt semper malesuada. Vestibulum at tellus massa. Nulla nec lobortis urna. Duis lobortis pharetra odio, sed mattis quam congue non. Fusce elementum nisl metus, eget ultricies ex aliquet vel. Praesent fermentum tellus imperdiet rutrum fermentum. Donec mauris sapien, convallis non condimentum id, vehicula in diam. Nunc odio nisi, vehicula eu metus eu, lobortis faucibus sapien. Integer pulvinar maximus mauris, vel commodo est fringilla rhoncus.

Nam rutrum egestas molestie. Praesent urna odio, egestas quis ante in, rhoncus fermentum nisi. Ut pulvinar diam id tortor bibendum, mattis luctus nulla vulputate. Mauris arcu augue, imperdiet quis metus non, porttitor fringilla erat. Nulla vel venenatis elit, in placerat lectus. Fusce dui ante, commodo sit amet laoreet at, luctus quis ligula. In feugiat nibh a augue sollicitudin, eget pellentesque massa maximus. Aenean a velit id est cursus aliquam nec vel leo. Vestibulum non efficitur libero, non sodales felis. Cras a mauris eu metus mattis mollis. Integer ac nibh congue, iaculis arcu et, vestibulum ex. Sed vel orci blandit, blandit leo id, viverra enim. In lobortis diam sit amet risus cursus ultricies. Aliquam molestie porttitor velit, pellentesque placerat ligula pulvinar in. Vestibulum porta, est vitae elementum ultricies, turpis dolor lacinia nunc, id facilisis ante sem vehicula justo.

Nullam interdum sagittis ligula, id fringilla quam dignissim in. Vestibulum ac massa et lectus hendrerit finibus nec a lorem. Aenean at elementum enim, eu rhoncus purus. Maecenas porttitor sapien nec tristique rhoncus. Donec tortor velit, ultricies at posuere sed, laoreet sit amet nunc. In nulla magna, imperdiet ut ipsum eu, vehicula bibendum turpis. Etiam sed magna quis lectus tristique elementum. Aliquam felis nisi, varius eget turpis nec, volutpat tincidunt lectus. Donec elit massa, dapibus id velit eget, sodales vehicula ligula. Vestibulum varius libero lacinia auctor rhoncus. Aliquam placerat urna dolor, sit amet fringilla velit vehicula at. Nam quis nisl cursus, tempor eros quis, venenatis lorem.

Quisque a lectus in velit tincidunt sollicitudin a non sem. Proin feugiat orci et semper tempor. Nulla vulputate orci eu consectetur sagittis. Morbi auctor dui sit amet eros varius volutpat. Quisque in neque elit. Integer sollicitudin felis mattis, efficitur lorem et, vulputate odio. Etiam at augue ut libero tempus dapibus vitae varius purus. Sed in ipsum a neque faucibus placerat at ut eros. Etiam euismod eros nunc, sed vulputate purus dignissim id. Quisque egestas purus turpis, sed cursus sapien porttitor eget. Aliquam placerat neque eget nisl consectetur, et lobortis dolor congue. Vivamus tellus sapien, convallis quis vehicula at, ultricies nec quam. Phasellus arcu lacus, malesuada id est accumsan, ultricies viverra massa. Ut lorem sapien, lacinia sit amet metus id, vehicula vulputate eros. Aliquam lorem sapien, semper ac vehicula sit amet, efficitur sagittis lectus. Integer vel sapien aliquet, tempor augue ut, molestie libero.

</div>

Aside: How do I get percentages?

You would simply modify the above formula from:

 scrollHeight - height

To:

scrollTop / ( scrollHeight -  height) * 100

Percentage Example:

demo.addEventListener("scroll", function(e) {
let {scrollTop, scrollHeight} = e.currentTarget,
height = +getComputedStyle(e.currentTarget)["height"].slice(0,-2);

console.log("Scrolled " + parseInt((parseInt(scrollTop) / parseInt(scrollHeight -  height)) * 100) + "% / 100% ");
});

html, body {
overflow: hidden;
}
div {
position: relative;
width: 50%;
left: calc(50% - 25%);
overflow: auto;
height: 101vh;
background: rgba(20,20,100, .3);
padding: 0px;
margin: 0px;
}

<div id="demo">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec tellus mauris, molestie eu vehicula quis, suscipit quis nisl. Fusce lorem purus, rhoncus eget dui nec, sagittis tincidunt odio. Interdum et malesuada fames ac ante ipsum primis in faucibus. Etiam eget odio vitae nulla porttitor maximus a eget neque. Pellentesque dictum mollis ligula, a consequat tellus feugiat vitae. Donec rutrum elementum odio, vitae egestas tellus volutpat nec. Proin tempor, odio quis molestie iaculis, lectus nibh volutpat turpis, luctus rutrum ex felis sit amet velit. Donec blandit cursus tortor in malesuada. Vestibulum faucibus, lectus vel accumsan molestie, ligula velit pharetra leo, ac imperdiet nibh quam quis mi.

Pellentesque ac dui augue. Fusce sit amet condimentum dui. Donec sodales urna nec nisl commodo, ac porta magna consectetur. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec tincidunt tellus nunc, at accumsan orci scelerisque sed. Suspendisse facilisis feugiat massa, quis egestas sapien tempus nec. Curabitur nunc ipsum, ultricies sit amet nibh sed, tincidunt tristique diam. Cras sit amet scelerisque leo, a blandit dolor. Cras lobortis leo nec est luctus molestie. Curabitur non arcu malesuada, tincidunt dolor quis, bibendum orci. Vestibulum lobortis tortor ac erat consequat, ut consequat ex consectetur. Maecenas finibus efficitur orci, sit amet gravida ipsum vestibulum a. Aliquam quis dictum mi. Vivamus sagittis fringilla quam, sed feugiat libero lobortis nec. Praesent suscipit nulla at mollis rutrum. Sed et lacus at quam feugiat varius vitae et lectus.

Suspendisse feugiat lacus eget risus elementum convallis. Vestibulum fringilla mi ac mollis sagittis. Suspendisse vel sem tincidunt, condimentum urna at, dignissim magna. Curabitur pulvinar lectus eu massa pharetra facilisis. Quisque est nisl, feugiat vitae pellentesque vel, hendrerit sed enim. Ut at dui eget eros rhoncus venenatis malesuada sit amet ligula. Pellentesque cursus vulputate egestas. Sed euismod sem vel felis sollicitudin faucibus. Cras aliquet viverra turpis sit amet pulvinar. Aliquam pellentesque dolor a pulvinar egestas. Curabitur in sagittis sapien. Vestibulum nec ipsum a risus porttitor rhoncus vitae id ex. Ut mollis, ligula eu sollicitudin commodo, nibh nibh bibendum mi, vel luctus tellus est eget eros.

Aenean congue diam id urna tincidunt consectetur. Nunc vel semper ligula. Sed ultrices, odio eu venenatis interdum, ligula velit volutpat nisl, et malesuada eros massa id ante. Sed malesuada non nisl quis imperdiet. Praesent porta fringilla fermentum. Integer id massa at orci mollis accumsan in et dolor. Nullam nisi lectus, dignissim a dapibus id, posuere sed ex. Praesent consequat, dui non imperdiet aliquam, magna diam rhoncus enim, id molestie mauris nunc eget ante. Morbi et laoreet sapien, tempor malesuada tellus. Pellentesque lectus leo, egestas eget faucibus vitae, dapibus non enim. Duis eu leo sit amet augue molestie laoreet eu ut ipsum. Vestibulum nulla enim, tempus id varius ut, egestas non elit.

Sed tincidunt lorem sed tellus lobortis vulputate. Aliquam vel accumsan massa, id ornare arcu. Phasellus non erat ut erat mollis placerat. Aliquam laoreet laoreet eros, in elementum ex maximus quis. Pellentesque in dui at purus efficitur mattis. Etiam consequat, nunc vel feugiat fringilla, ante enim aliquet tellus, nec dapibus dui justo eget nibh. Praesent enim leo, tincidunt a dictum et, mollis at neque.

Fusce maximus, enim sed congue tempus, lorem tellus hendrerit massa, eget eleifend augue nisi eget eros. Aliquam vehicula eu enim et interdum. Nullam sollicitudin nisl sapien, quis euismod dolor vestibulum eget. Curabitur consectetur, nulla quis scelerisque tincidunt, sem turpis sagittis lacus, at tincidunt nunc felis et velit. Quisque nec malesuada lectus. Cras a lorem fermentum, tincidunt dolor a, dictum eros. Suspendisse augue tellus, cursus et ex sit amet, cursus sodales nibh. Pellentesque quis lacus aliquam libero bibendum eleifend. Interdum et malesuada fames ac ante ipsum primis in faucibus. Proin eget justo nec velit ultrices porttitor. Aenean vel accumsan arcu, sit amet finibus eros.

Sed ut convallis tortor, non dictum odio. Cras eu dictum sem. Cras laoreet lectus quis sapien volutpat bibendum. Vivamus ut finibus magna. Nunc aliquet tincidunt blandit. Pellentesque nisl tortor, malesuada eu est sed, congue fermentum nibh. Curabitur eu tellus nibh. Mauris quis eleifend lacus, id lacinia erat. Suspendisse id purus mauris. Cras ornare neque ac nulla blandit, eget faucibus turpis dictum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum mattis faucibus massa. Ut dignissim justo eget malesuada iaculis. Integer venenatis malesuada euismod. Nulla sollicitudin justo non consequat pharetra. Donec ultrices mi at neque tincidunt, in scelerisque sem vehicula.

Integer ac consectetur enim. Nunc sed fringilla magna. Nullam fermentum nisl nec venenatis condimentum. Mauris leo metus, convallis ut sem eu, tincidunt malesuada nunc. Cras metus lacus, sagittis ut convallis non, tempor vel turpis. Sed ultricies tristique odio id cursus. Praesent auctor ac ipsum faucibus ultrices. Donec id metus a sem aliquet suscipit. Maecenas mi sem, posuere non turpis id, vehicula placerat arcu. Curabitur tincidunt viverra neque ac pharetra. Curabitur vitae massa vehicula lorem tristique tempor. Duis congue nunc id lacus suscipit, ut laoreet enim malesuada.

Ut velit tellus, rhoncus a gravida id, aliquam quis dolor. Nam elementum purus non leo porttitor tempus. Curabitur tempor feugiat magna ac tempus. Ut cursus ultricies rutrum. Duis a feugiat arcu. Nullam bibendum metus sed nulla feugiat scelerisque vitae nec sem. Mauris aliquam vestibulum dui a commodo. Cras vel molestie metus. Quisque ac arcu odio. Phasellus pretium a leo non lacinia. Mauris et odio dui. Praesent commodo lorem eu erat pulvinar tincidunt. Praesent sagittis interdum mauris, eu egestas dolor volutpat dignissim. Duis posuere, arcu nec placerat ullamcorper, lectus nunc tempor mauris, vitae congue lacus arcu at enim.

Quisque eu massa sit amet dui accumsan pulvinar. Ut fermentum lectus eros, at iaculis enim consectetur quis. Ut semper, mi in vehicula lacinia, purus mi sagittis orci, rhoncus tristique magna leo vel purus. In congue feugiat arcu consequat pretium. Vestibulum sit amet pellentesque neque, a dignissim nisl. Maecenas ac dolor id justo feugiat varius vel sed turpis. Donec quis mi id nibh condimentum dictum. Mauris dapibus justo quam, ut fermentum diam ultrices et. Cras lobortis leo et finibus congue. Integer sed dui id mi efficitur efficitur. Quisque id gravida magna. Duis pharetra cursus metus vel pellentesque. Integer at magna ante. Donec aliquam nulla sem, at rhoncus ex tincidunt aliquam. Vestibulum sit amet hendrerit diam.

Mauris imperdiet dui eget massa malesuada mollis. Integer consectetur varius justo sit amet posuere. Aenean semper est at justo pulvinar finibus. Nunc ac maximus dui, a euismod orci. Mauris congue orci in ullamcorper pellentesque. Etiam tincidunt lorem id diam maximus elementum. Etiam in erat libero. Curabitur vehicula sodales mi, quis iaculis nulla consequat nec. Sed cursus lectus sed velit commodo, eu ultricies sapien pulvinar.

Nulla rutrum lacus est, vel lacinia ipsum euismod congue. Nunc vel vehicula orci. Sed eget nibh in dolor volutpat scelerisque. Ut porta viverra est, sed sollicitudin lorem euismod id. Proin interdum, lorem in luctus gravida, justo elit laoreet ante, nec malesuada diam mi ut lacus. Nunc nisl mi, hendrerit rutrum ligula id, auctor commodo ligula. Donec ullamcorper scelerisque sapien, vel feugiat justo molestie sed. Curabitur faucibus dignissim urna. Cras at sodales ante.

In varius, odio et feugiat hendrerit, lectus mauris faucibus mauris, at vulputate quam tellus vel sem. Fusce posuere turpis sem, porta imperdiet lorem feugiat a. Morbi iaculis dui nec accumsan scelerisque. Duis elit diam, fermentum non diam pretium, molestie venenatis nisl. Suspendisse faucibus dapibus ipsum nec placerat. Nulla sed pretium enim. Cras semper iaculis lacinia. Cras id vulputate orci, quis tristique ante. Phasellus nec suscipit tortor, viverra elementum augue.

Duis sed finibus dui. Nunc molestie vestibulum egestas. Sed in nisi dapibus, vehicula sem in, mattis orci. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Quisque ut interdum lacus, id pulvinar risus. Donec blandit non sapien vitae gravida. Interdum et malesuada fames ac ante ipsum primis in faucibus.

Sed sit amet odio ut nulla consequat consectetur quis ut ipsum. Donec mollis sed neque quis luctus. Sed malesuada hendrerit tempor. Sed interdum maximus maximus. Cras placerat vel leo non fringilla. Praesent tincidunt semper malesuada. Vestibulum at tellus massa. Nulla nec lobortis urna. Duis lobortis pharetra odio, sed mattis quam congue non. Fusce elementum nisl metus, eget ultricies ex aliquet vel. Praesent fermentum tellus imperdiet rutrum fermentum. Donec mauris sapien, convallis non condimentum id, vehicula in diam. Nunc odio nisi, vehicula eu metus eu, lobortis faucibus sapien. Integer pulvinar maximus mauris, vel commodo est fringilla rhoncus.

Nam rutrum egestas molestie. Praesent urna odio, egestas quis ante in, rhoncus fermentum nisi. Ut pulvinar diam id tortor bibendum, mattis luctus nulla vulputate. Mauris arcu augue, imperdiet quis metus non, porttitor fringilla erat. Nulla vel venenatis elit, in placerat lectus. Fusce dui ante, commodo sit amet laoreet at, luctus quis ligula. In feugiat nibh a augue sollicitudin, eget pellentesque massa maximus. Aenean a velit id est cursus aliquam nec vel leo. Vestibulum non efficitur libero, non sodales felis. Cras a mauris eu metus mattis mollis. Integer ac nibh congue, iaculis arcu et, vestibulum ex. Sed vel orci blandit, blandit leo id, viverra enim. In lobortis diam sit amet risus cursus ultricies. Aliquam molestie porttitor velit, pellentesque placerat ligula pulvinar in. Vestibulum porta, est vitae elementum ultricies, turpis dolor lacinia nunc, id facilisis ante sem vehicula justo.

Nullam interdum sagittis ligula, id fringilla quam dignissim in. Vestibulum ac massa et lectus hendrerit finibus nec a lorem. Aenean at elementum enim, eu rhoncus purus. Maecenas porttitor sapien nec tristique rhoncus. Donec tortor velit, ultricies at posuere sed, laoreet sit amet nunc. In nulla magna, imperdiet ut ipsum eu, vehicula bibendum turpis. Etiam sed magna quis lectus tristique elementum. Aliquam felis nisi, varius eget turpis nec, volutpat tincidunt lectus. Donec elit massa, dapibus id velit eget, sodales vehicula ligula. Vestibulum varius libero lacinia auctor rhoncus. Aliquam placerat urna dolor, sit amet fringilla velit vehicula at. Nam quis nisl cursus, tempor eros quis, venenatis lorem.

Quisque a lectus in velit tincidunt sollicitudin a non sem. Proin feugiat orci et semper tempor. Nulla vulputate orci eu consectetur sagittis. Morbi auctor dui sit amet eros varius volutpat. Quisque in neque elit. Integer sollicitudin felis mattis, efficitur lorem et, vulputate odio. Etiam at augue ut libero tempus dapibus vitae varius purus. Sed in ipsum a neque faucibus placerat at ut eros. Etiam euismod eros nunc, sed vulputate purus dignissim id. Quisque egestas purus turpis, sed cursus sapien porttitor eget. Aliquam placerat neque eget nisl consectetur, et lobortis dolor congue. Vivamus tellus sapien, convallis quis vehicula at, ultricies nec quam. Phasellus arcu lacus, malesuada id est accumsan, ultricies viverra massa. Ut lorem sapien, lacinia sit amet metus id, vehicula vulputate eros. Aliquam lorem sapien, semper ac vehicula sit amet, efficitur sagittis lectus. Integer vel sapien aliquet, tempor augue ut, molestie libero.

</div>


问:
python: how to send mail with TO, CC and BCC?
I need for testing purposes to populate few hundred email boxes with various messages, and was going to use smtplib for that. But among other things I need to be able to send messages not only TO specific mailboxes, but CC and BCC them as well. It does not look like  smtplib  supports CC-ing and BCC-ing while sending emails.

Looking for suggestions how to do CC or BCC sending messages from the python script.

(And — no, I'm not creating a script to spam anyone outside of my testing environment.)

答:
As of Python 3.2, released Nov 2011, the smtplib has a new function send_message instead of just sendmail, which makes dealing with To/CC/BCC easier. Pulling from the Python official email examples, with some slight modifications, we get:

```<code># Import smtplib for the actual sending function
import smtplib

# Import the email modules we'll need
from email.message import EmailMessage

# Open the plain text file whose name is in textfile for reading.
with open(textfile) as fp:
    # Create a text/plain message
    msg = EmailMessage()
    msg.set_content(fp.read())

# me == the sender's email address
# you == the recipient's email address
# them == the cc's email address
# they == the bcc's email address
msg['Subject'] = 'The contents of %s' % textfile
msg['From'] = me
msg['To'] = you
msg['Cc'] = them
msg['Bcc'] = they

# Send the message via our own SMTP server.
s = smtplib.SMTP('localhost')
s.send_message(msg)
s.quit()
</code>```

Using the headers work fine, because send_message respects BCC as outlined in the documentation:

send_message does not transmit any Bcc or Resent-Bcc headers that may appear in msg

With sendmail it was common to add the CC headers to the message, doing something such as:

```<code>msg['Bcc'] = blind.email@adrress.com
</code>```

Or

```<code>msg = "From: from.email@address.com" +
      "To: to.email@adress.com" +
      "BCC: hidden.email@address.com" +
      "Subject: You've got mail!" +
      "This is the message body"
</code>```

The problem is, the sendmail function treats all those headers the same, meaning they'll get sent (visibly) to all To: and BCC: users, defeating the purposes of BCC. The solution, as shown in many of the other answers here, was to not include BCC in the headers, and instead only in the list of emails passed to sendmail.

The caveat is that send_message requires a Message object, meaning you'll need to import a class from email.message instead of merely passing strings into sendmail.

Body:
As of Python 3.2, released Nov 2011, the smtplib has a new function send_message instead of just sendmail, which makes dealing with To/CC/BCC easier. Pulling from the Python official email examples, with some slight modifications, we get:

# Import smtplib for the actual sending function
import smtplib

# Import the email modules we'll need
from email.message import EmailMessage

# Open the plain text file whose name is in textfile for reading.
with open(textfile) as fp:
    # Create a text/plain message
    msg = EmailMessage()
    msg.set_content(fp.read())

# me == the sender's email address
# you == the recipient's email address
# them == the cc's email address
# they == the bcc's email address
msg['Subject'] = 'The contents of %s' % textfile
msg['From'] = me
msg['To'] = you
msg['Cc'] = them
msg['Bcc'] = they

# Send the message via our own SMTP server.
s = smtplib.SMTP('localhost')
s.send_message(msg)
s.quit()

Using the headers work fine, because send_message respects BCC as outlined in the documentation:

send_message does not transmit any Bcc or Resent-Bcc headers that may appear in msg

With sendmail it was common to add the CC headers to the message, doing something such as:

msg['Bcc'] = blind.email@adrress.com

Or

msg = "From: from.email@address.com" +
      "To: to.email@adress.com" +
      "BCC: hidden.email@address.com" +
      "Subject: You've got mail!" +
      "This is the message body"

The problem is, the sendmail function treats all those headers the same, meaning they'll get sent (visibly) to all To: and BCC: users, defeating the purposes of BCC. The solution, as shown in many of the other answers here, was to not include BCC in the headers, and instead only in the list of emails passed to sendmail.

The caveat is that send_message requires a Message object, meaning you'll need to import a class from email.message instead of merely passing strings into sendmail.


问:
How to count number of emails and average of emails sent by hour?
I'm working on reports with Power BI. I want to get for each hour the number of emails sent. I did the query in SQL Server but I'm having a difficulty translating it to DAX to create a measure.Also I want to get the average number of emails sent by hour.

My query is like below  :

```<code> select datepart(hour,CreatedDate), count(MailId) from [DW PI].[dbo].[Email Fact]
      group by datepart(hour,CreatedDate)
      order by count(MailId) desc
</code>```

答:
You need to create an extra column on your table:

```<code>Hour = HOUR(Email Fact[CreatedDate])
</code>```

Now you add this column to your table visual together with the MailId.

Last point: you want a count of the MailId, not the Sum.
For you that is the count of MailId

Body:
I'm working on reports with Power BI. I want to get for each hour the number of emails sent. I did the query in SQL Server but I'm having a difficulty translating it to DAX to create a measure.Also I want to get the average number of emails sent by hour.

My query is like below  :

 select datepart(hour,CreatedDate), count(MailId) from [DW PI].[dbo].[Email Fact]
      group by datepart(hour,CreatedDate)
      order by count(MailId) desc

Body:
You need to create an extra column on your table:

Hour = HOUR(Email Fact[CreatedDate])

Now you add this column to your table visual together with the MailId.

Last point: you want a count of the MailId, not the Sum.
For you that is the count of MailId


问:
How to get value of row in a word table with VBA
I'm trying to delete the last row of a word table when there is no data on a specific row in a Word Table using VBA. But so far all it does is delete the last row and throw an error of a missing object.

I tried setting the Text property as the documentation says like this:

```<code>Set VCell = objTable2.Cell(j,2).Range.Text
</code>```

But it's not working as it throws an error stating that the string object is required.

This is the code I am using to perform the delete:

```<code>   If j < 9 Then

        For i = 1 To Ubound(TC_STP_Array)

            objTable2.Rows.Last.Select

            Set VCell = objTable2.Cell(j,2).Range.Text

            If objTable2.Rows.Last.IsLast and VCell = "" Then
                objTable2.Rows.Last.Cells.Delete
            End If

         Next
End if
</code>```

The first error I get is:

Object Required:'[string "•"]'

on the line:

```<code>Set VCell = objTable2.Cell(j,2).Range.Text
</code>```

and when there is data on the row, I get this:

Object Required:'[string "Test•"]'

Any Ideas on how to solve this?

答:
Solved by removing the Set word
VCell = objTable2.Cell(j,2).Range.Text
Since it is not an object and it is only required for objects not strings.</p>

Body:
I'm trying to delete the last row of a word table when there is no data on a specific row in a Word Table using VBA. But so far all it does is delete the last row and throw an error of a missing object.

I tried setting the Text property as the documentation says like this:

Set VCell = objTable2.Cell(j,2).Range.Text

But it's not working as it throws an error stating that the string object is required.

This is the code I am using to perform the delete:

   If j < 9 Then

        For i = 1 To Ubound(TC_STP_Array)

            objTable2.Rows.Last.Select

            Set VCell = objTable2.Cell(j,2).Range.Text

            If objTable2.Rows.Last.IsLast and VCell = "" Then
                objTable2.Rows.Last.Cells.Delete
            End If

         Next
End if

The first error I get is:

Object Required:'[string "•"]'

on the line:

Set VCell = objTable2.Cell(j,2).Range.Text

and when there is data on the row, I get this:

Object Required:'[string "Test•"]'

Any Ideas on how to solve this?


问:
Center different size images in the same block size
I have different images encapsulated in square style blocks that I would like to always center in but I'm having a heck of a time trying to get them to do so.

I made an example of what's happening to me in similar design. Notice the product (the grill) is not actually centered in the imgblock container.

This starts to become very apparent with other product images that are much wider than narrow.

.imgBlock {
  width:100px;
  height:100px;
  border:2px solid black;
  margin:1px;
  padding:4px;
}

.imgBlock img{
  max-height:100%;
  max-width:100%;
  margin:auto;
  display:block;
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div class="container">
  <div class="imgBlock">
    <img src="https://cdn.shopify.com/s/files/1/1150/2512/t/41/assets/WG-logo-short-black.png?43066">
  </div>
  <div class="imgBlock">
    <img src="https://cdn.shopify.com/s/files/1/1150/2512/t/41/assets/M1-Grill-FAQ.jpg?43066">
  </div>
</div></code>```

答:
You can set position relative to your div .imgBlock.
After that set the position absolute to your  with all coordinates to 0 and margin auto.

Remember that a position absolute is referred to the nearest parent with position relative.

.imgBlock {
  width:100px;
  height:100px;
  border:2px solid black;
  margin:1px;
  padding:4px;
  position:relative;
}

.imgBlock img{
  max-height:100%;
  max-width:100%;
  position: absolute;
  margin: auto;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div class="container">
  <div class="imgBlock">
    <img src="https://cdn.shopify.com/s/files/1/1150/2512/t/41/assets/WG-logo-short-black.png?43066">
  </div>
  <div class="imgBlock">
    <img src="https://cdn.shopify.com/s/files/1/1150/2512/t/41/assets/M1-Grill-FAQ.jpg?43066">
  </div>
</div></code>```

Body:
You can set position relative to your div .imgBlock.
After that set the position absolute to your <img/> with all coordinates to 0 and margin auto.

Remember that a position absolute is referred to the nearest parent with position relative.

.imgBlock {
  width:100px;
  height:100px;
  border:2px solid black;
  margin:1px;
  padding:4px;
  position:relative;
}

.imgBlock img{
  max-height:100%;
  max-width:100%;
  position: absolute;
  margin: auto;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

<div class="container">
  <div class="imgBlock">
    <img src="https://cdn.shopify.com/s/files/1/1150/2512/t/41/assets/WG-logo-short-black.png?43066">
  </div>
  <div class="imgBlock">
    <img src="https://cdn.shopify.com/s/files/1/1150/2512/t/41/assets/M1-Grill-FAQ.jpg?43066">
  </div>
</div>


问:
Change parent layout by child button on that layout
I have problem with change of tab panel layout by click event on buton located on that panel. The main idea is to have custom menu (new, open, del) on smal panel on every tab panel. When you click button, tab panel layout is change to form (for example). I don't want use modal window or new window, just change the tab panel layout (content) to something else by button click.</p>

答:
It, is wrong specified question - you should ask how to notify parent component.
Bellow you have two examples show how to achive your goals. This first implementation does what Jens Janssons suggest on vaadin forum, you pass the ClickListener to the second panel as a constructor parameter. Note that to be able to remove the component from the outer panel, you need both a reference to the outer panel and to the inner panel. In this example Kim Lappanen stored the references in class variables. Note that ther is actually used a HorizontalLayout for what you called your "panel", you can change it.

```<code>public class TestcaseApplication extends Application implements ClickListener {
    private static final long serialVersionUID = 75232258896642392L;

    private final HorizontalLayout mainLayout = new HorizontalLayout();
    private final YourPanel panel = new YourPanel(this);

    @Override
    public void init() {
        setTheme("example");
        Window mainWindow = new Window("Playground Application");
        setMainWindow(mainWindow);

        mainWindow.setContent(mainLayout);

        mainLayout.addComponent(panel);
    }

    public void buttonClick(ClickEvent event) {
        mainLayout.removeComponent(panel);
    }

    public class YourPanel extends Panel {

        public YourPanel(ClickListener listener) {
            super();
            addComponent(new Button("Remove", listener));
        }
    }
}
</code>```

Antoher example is to implement the ClickListener directly in the inner panel. In the buttonClick method, I just call getParent() (returns the out layout) and then removes itself from that layout.

```<code>public class TestcaseApplication extends Application {
    private static final long serialVersionUID = 75232258896642392L;

    @Override
    public void init() {
        setTheme("example");
        Window mainWindow = new Window("Playground Application");
        setMainWindow(mainWindow);

        HorizontalLayout mainLayout = new HorizontalLayout();
        mainWindow.setContent(mainLayout);

        mainLayout.addComponent(new YourPanel());
    }

    public class YourPanel extends Panel implements ClickListener {

        public YourPanel() {
            super();
            addComponent(new Button("Remove", this));

        }

        public void buttonClick(ClickEvent event) {
            ((ComponentContainer) getParent()).removeComponent(this);
        }
    }

}
</code>```

Body:
It, is wrong specified question - you should ask how to notify parent component.
Bellow you have two examples show how to achive your goals. This first implementation does what Jens Janssons suggest on vaadin forum, you pass the ClickListener to the second panel as a constructor parameter. Note that to be able to remove the component from the outer panel, you need both a reference to the outer panel and to the inner panel. In this example Kim Lappanen stored the references in class variables. Note that ther is actually used a HorizontalLayout for what you called your "panel", you can change it.

public class TestcaseApplication extends Application implements ClickListener {
    private static final long serialVersionUID = 75232258896642392L;

    private final HorizontalLayout mainLayout = new HorizontalLayout();
    private final YourPanel panel = new YourPanel(this);

    @Override
    public void init() {
        setTheme("example");
        Window mainWindow = new Window("Playground Application");
        setMainWindow(mainWindow);

        mainWindow.setContent(mainLayout);

        mainLayout.addComponent(panel);
    }

    public void buttonClick(ClickEvent event) {
        mainLayout.removeComponent(panel);
    }

    public class YourPanel extends Panel {

        public YourPanel(ClickListener listener) {
            super();
            addComponent(new Button("Remove", listener));
        }
    }
}

Antoher example is to implement the ClickListener directly in the inner panel. In the buttonClick method, I just call getParent() (returns the out layout) and then removes itself from that layout.

public class TestcaseApplication extends Application {
    private static final long serialVersionUID = 75232258896642392L;

    @Override
    public void init() {
        setTheme("example");
        Window mainWindow = new Window("Playground Application");
        setMainWindow(mainWindow);

        HorizontalLayout mainLayout = new HorizontalLayout();
        mainWindow.setContent(mainLayout);

        mainLayout.addComponent(new YourPanel());
    }

    public class YourPanel extends Panel implements ClickListener {

        public YourPanel() {
            super();
            addComponent(new Button("Remove", this));

        }

        public void buttonClick(ClickEvent event) {
            ((ComponentContainer) getParent()).removeComponent(this);
        }
    }

}


问:
Getting Excel sheet cell value next to a merged column
I have an Excel sheet formatted as the image below.

I would like to retrieve the list of cell texts next to a merged column. I am thinking something of this kind. My idea is to get the total number of merged cells and then iterate over the next set of cells. I cannot find any method in Range that returns the total number of cells in a merged cell. The properties EntireRow and EntireColumn doesn't give the total number of cells merged. Any hints would be helpful.

```<code>List<String> GetNextTexts(Microsoft.Office.Interop.Excel.Range range)
{}
</code>```

Examples

GetNextTexts(rangeTest) should return {TestRx, TestSPC}

GetNextTexts(rangeTestRx) should return {P4_7, P0_0, P0_14, P3_2}

GetNextTexts(rangeTestSPC) should return {P2_4}

答:
Here are some Range properties that can be useful (assuming rangeTest is in B2:B6) :

rangeTest = Range["B2"].MergeArea gives the range of the merged cell Test - B2:B6

rangeTest.Rows.Count and rangeTest.Count give the number of rows and number of cells  - 5

rangeTest.Offset[0, 1] gives the range C2, and .MergeArea of that gives the rangeTestRx.

rangeTestRx.Count can be used to get the number of cells in rangeTestRx (4), and compare that to the number of cells in rangeTest to check if there is another cell below rangeTestRx.

rangeTestRx.Offset[4, 0] can be used to get the Range below rangeTestRx - C6 and so on.

Body:
I have an Excel sheet formatted as the image below.

I would like to retrieve the list of cell texts next to a merged column. I am thinking something of this kind. My idea is to get the total number of merged cells and then iterate over the next set of cells. I cannot find any method in Range that returns the total number of cells in a merged cell. The properties EntireRow and EntireColumn doesn't give the total number of cells merged. Any hints would be helpful.

List<String> GetNextTexts(Microsoft.Office.Interop.Excel.Range range)
{}

Examples

GetNextTexts(rangeTest) should return {TestRx, TestSPC}

GetNextTexts(rangeTestRx) should return {P4_7, P0_0, P0_14, P3_2}

GetNextTexts(rangeTestSPC) should return {P2_4}