Re: datomic question

2013-03-08 Thread Paul Gearon
On Monday, 4 March 2013 01:50:56 UTC-5, edw...@kenworthy.info wrote:

 Okay, I think I understand that.

 Does that mean this code could never work as intended in a Clojure 
 program, only at the repl (which seems a bit of a limitation) or is there a 
 way to make it work as intended, generating a different id each time? Or is 
 the whole approach taken in this code flawed?


The tagged literal approach is best used if you need to store the entity 
and read it back using edn. So it's perfect for using in a data file.

However, if you're generating data in code you've already seen how this can 
cause problems. In that case, you do what Jonas suggests and use tempid 
(with the appropriate partition keyword. e.g. :db.part/user).

The two approaches offer different tradeoffs. tempid is a function, and can 
only appear in code (not a data file, or anything else read by edn). 
Conversely, if the the tagged literal appears in code, then it's possible 
for it to be referred to more than once in the same transaction, which is 
almost guaranteed to be counter to what you want.

Paul

-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.




Re: datomic question

2013-03-04 Thread edward
Thanks very much Michael and Jonas.

On Monday, 4 March 2013 07:20:24 UTC, Jonas wrote:

 Hi

 You can use the tempid (
 http://docs.datomic.com/clojure/index.html#datomic.api/tempid) function 
 to generate new temporary ids.

 Jonas

 On Monday, March 4, 2013 8:50:56 AM UTC+2, edw...@kenworthy.info wrote:

 Okay, I think I understand that.

 Does that mean this code could never work as intended in a Clojure 
 program, only at the repl (which seems a bit of a limitation) or is there a 
 way to make it work as intended, generating a different id each time? Or is 
 the whole approach taken in this code flawed?

 On Sunday, 3 March 2013 21:59:45 UTC, Michał Marczyk wrote:

 #db/id ... is a tagged literal. It gets read in as an id object with 
 some integer inside. The way this happens is that the reader looks up 
 a data reader function associated with the symbol db/id in the map 
 held by the var *data-readers* and passes to it the result of parsing 
 the rest of the literal (a vector holding the keyword :db.part/db in 
 this case). Importantly, this function is not pure and the integer it 
 uses will be different on each invocation. (Given this form of the 
 #db/id literal; you can also specify a particular number yourself -- 
 #db/id [:db.part/db some-number-here].) 

 In any case, once the reader reads in your code including some 
 particular id, the compiler will compile the result preserving the 
 particular values it sees, so it will embed code to construct *exactly 
 this* id in the compiled output. Thus you end up with a particular id 
 hardwired into the first version of your function. 

 With the second version, if you invoke it multiple times at the REPL, 
 you ask the reader for a new id at each invocation, so it works as you 
 expect. If instead you were to use it inside a function like so: 

 (defn foo [] 
   (make-column-schema #db/id [:db.part/db] :results/subject 
 :db.type/string)), 

 then again the same id would be used for every (foo) call. 

 Cheers, 
 Michał 


 On 3 March 2013 21:58,  edw...@kenworthy.info wrote: 
  So, I am studying a piece of code from the web. I've dissected most of 
 it 
  and am in the process of re-factoring it. 
  
  What I don't understand is why one version works and the other 
 doesn't. 
  
  So for both: 
  
  (ns gcse-results.core (:use [datomic.api :only [q db] :as d]) (:use 
  quil.core)) 
  
  This doesn't work: 
  
  (defn make-column-schema [db-ident db-type] 
  {:db/id #db/id[:db.part/db] 
  :db/ident db-ident 
  :db/valueType db-type 
  :db/cardinality :db.cardinality/one 
  :db.install/_attribute :db.part/db}) 
  
  Each call to: 
  
  (make-column-schema :results/subject :db.type/string) 
  
  The value of #db/id[:db.part/db] is the same. 
  
  And this works: 
  
  (defn make-column-schema [db-id db-ident db-type] 
  {:db/id db-id 
  :db/ident db-ident 
  :db/valueType db-type 
  :db/cardinality :db.cardinality/one 
  :db.install/_attribute :db.part/db}) 
  
  Each call to: (make-column-schema #db/id[:db.part/db] :results/subject 
  :db.type/string) 
  
  The value of #db/id[:db.part/db] is the different, as expected. 
  
  Now I thought that I understood #db/id[:db.part/db] (call to a Java 
  constructor) but obviously my understanding is flawed as I would 
 expect both 
  of these functions to produce the same thing, but they don't so 
 there's 
  obviously some gap in my understanding. 
  
  Help? 
  
  -- 
  -- 
  You received this message because you are subscribed to the Google 
  Groups Clojure group. 
  To post to this group, send email to clo...@googlegroups.com 
  Note that posts from new members are moderated - please be patient 
 with your 
  first post. 
  To unsubscribe from this group, send email to 
  clojure+u...@googlegroups.com 
  For more options, visit this group at 
  http://groups.google.com/group/clojure?hl=en 
  --- 
  You received this message because you are subscribed to the Google 
 Groups 
  Clojure group. 
  To unsubscribe from this group and stop receiving emails from it, send 
 an 
  email to clojure+u...@googlegroups.com. 
  For more options, visit https://groups.google.com/groups/opt_out. 
  
  



-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.




Re: datomic question

2013-03-04 Thread larry google groups
This page:

http://clojure.org/reader

Offers this explanation of what the # character does:

Dispatch (#)

The dispatch macro causes the reader to use a reader macro from
another table, indexed by the character following #:

#{} - see Sets above

Regex patterns (#pattern)
A regex pattern is read and compiled at read time. The resulting
object is of type java.util.regex.Pattern.

Var-quote (#')
#'x = (var x)

Anonymous function literal (#())
#(...) = (fn [args] (...))
where args are determined by the presence of argument literals taking
the form %, %n or %. % is a synonym for %1, %n designates the nth arg
(1-based), and % designates a rest arg. This is not a replacement for
fn - idiomatic used would be for very short one-off mapping/filter fns
and the like. #() forms cannot be nested.

Ignore next form (#_)
The form following #_ is completely skipped by the reader. (This is a
more complete removal than the comment macro which yields nil).

Although, for me personally, I felt like I better understood the
description given on the EDN page:

https://github.com/edn-format/edn

# dispatch character

Tokens beginning with # are reserved. The character following #
determines the behavior. The dispatches #{ (sets), #_ (discard),
#alphabetic-char (tag) are defined below. # is not a delimiter.

tagged elements
edn supports extensibility through a simple mechanism. # followed
immediately by a symbol starting with an alphabetic character
indicates that that symbol is a tag. A tag indicates the semantic
interpretation of the following element. It is envisioned that a
reader implementation will allow clients to register handlers for
specific tags. Upon encountering a tag, the reader will first read the
next element, then pass the result to the corresponding handler for
further interpretation, and the result of the handler will be the data
value yielded by the tag + tagged element, i.e. reading a tag and
tagged element yields one value. This value is the value to be
returned to the program and is not further interpreted as edn data by
the reader.

This process will bottom out on elements either understood or built-
in.

Thus you can build new distinct readable elements out of (and only out
of) other readable elements, keeping extenders and extension consumers
out of the text business.



On Mar 4, 3:24 am, edw...@kenworthy.info wrote:
 Thanks very much Michael and Jonas.







 On Monday, 4 March 2013 07:20:24 UTC, Jonas wrote:

  Hi

  You can use the tempid (
 http://docs.datomic.com/clojure/index.html#datomic.api/tempid) function
  to generate new temporary ids.

  Jonas

  On Monday, March 4, 2013 8:50:56 AM UTC+2, edw...@kenworthy.info wrote:

  Okay, I think I understand that.

  Does that mean this code could never work as intended in a Clojure
  program, only at the repl (which seems a bit of a limitation) or is there a
  way to make it work as intended, generating a different id each time? Or is
  the whole approach taken in this code flawed?

  On Sunday, 3 March 2013 21:59:45 UTC, Michał Marczyk wrote:

  #db/id ... is a tagged literal. It gets read in as an id object with
  some integer inside. The way this happens is that the reader looks up
  a data reader function associated with the symbol db/id in the map
  held by the var *data-readers* and passes to it the result of parsing
  the rest of the literal (a vector holding the keyword :db.part/db in
  this case). Importantly, this function is not pure and the integer it
  uses will be different on each invocation. (Given this form of the
  #db/id literal; you can also specify a particular number yourself --
  #db/id [:db.part/db some-number-here].)

  In any case, once the reader reads in your code including some
  particular id, the compiler will compile the result preserving the
  particular values it sees, so it will embed code to construct *exactly
  this* id in the compiled output. Thus you end up with a particular id
  hardwired into the first version of your function.

  With the second version, if you invoke it multiple times at the REPL,
  you ask the reader for a new id at each invocation, so it works as you
  expect. If instead you were to use it inside a function like so:

  (defn foo []
    (make-column-schema #db/id [:db.part/db] :results/subject
  :db.type/string)),

  then again the same id would be used for every (foo) call.

  Cheers,
  Michał

  On 3 March 2013 21:58,  edw...@kenworthy.info wrote:
   So, I am studying a piece of code from the web. I've dissected most of
  it
   and am in the process of re-factoring it.

   What I don't understand is why one version works and the other
  doesn't.

   So for both:

   (ns gcse-results.core (:use [datomic.api :only [q db] :as d]) (:use
   quil.core))

   This doesn't work:

   (defn make-column-schema [db-ident db-type]
       {:db/id #db/id[:db.part/db]
       :db/ident db-ident
       :db/valueType db-type
       :db/cardinality :db.cardinality/one
       :db.install/_attribute 

datomic question

2013-03-03 Thread edward


So, I am studying a piece of code from the web. I've dissected most of it 
and am in the process of re-factoring it.

What I don't understand is why one version works and the other doesn't.

So for both:

(ns gcse-results.core (:use [datomic.api :only [q db] :as d]) (:use 
quil.core))

This doesn't work:

(defn make-column-schema [db-ident db-type]
{:db/id #db/id[:db.part/db]
:db/ident db-ident
:db/valueType db-type
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}) 

Each call to:

(make-column-schema :results/subject :db.type/string)

The value of #db/id[:db.part/db] is the same.

And this works:

(defn make-column-schema [db-id db-ident db-type]
{:db/id db-id
:db/ident db-ident
:db/valueType db-type
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}) 

Each call to: (make-column-schema #db/id[:db.part/db] :results/subject 
:db.type/string)

The value of #db/id[:db.part/db] is the different, as expected.

Now I thought that I understood #db/id[:db.part/db] (call to a Java 
constructor) but obviously my understanding is flawed as I would expect 
both of these functions to produce the same thing, but they don't so 
there's obviously some gap in my understanding.

Help?

-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.




Re: datomic question

2013-03-03 Thread Michał Marczyk
#db/id ... is a tagged literal. It gets read in as an id object with
some integer inside. The way this happens is that the reader looks up
a data reader function associated with the symbol db/id in the map
held by the var *data-readers* and passes to it the result of parsing
the rest of the literal (a vector holding the keyword :db.part/db in
this case). Importantly, this function is not pure and the integer it
uses will be different on each invocation. (Given this form of the
#db/id literal; you can also specify a particular number yourself --
#db/id [:db.part/db some-number-here].)

In any case, once the reader reads in your code including some
particular id, the compiler will compile the result preserving the
particular values it sees, so it will embed code to construct *exactly
this* id in the compiled output. Thus you end up with a particular id
hardwired into the first version of your function.

With the second version, if you invoke it multiple times at the REPL,
you ask the reader for a new id at each invocation, so it works as you
expect. If instead you were to use it inside a function like so:

(defn foo []
  (make-column-schema #db/id [:db.part/db] :results/subject :db.type/string)),

then again the same id would be used for every (foo) call.

Cheers,
Michał


On 3 March 2013 21:58,  edw...@kenworthy.info wrote:
 So, I am studying a piece of code from the web. I've dissected most of it
 and am in the process of re-factoring it.

 What I don't understand is why one version works and the other doesn't.

 So for both:

 (ns gcse-results.core (:use [datomic.api :only [q db] :as d]) (:use
 quil.core))

 This doesn't work:

 (defn make-column-schema [db-ident db-type]
 {:db/id #db/id[:db.part/db]
 :db/ident db-ident
 :db/valueType db-type
 :db/cardinality :db.cardinality/one
 :db.install/_attribute :db.part/db})

 Each call to:

 (make-column-schema :results/subject :db.type/string)

 The value of #db/id[:db.part/db] is the same.

 And this works:

 (defn make-column-schema [db-id db-ident db-type]
 {:db/id db-id
 :db/ident db-ident
 :db/valueType db-type
 :db/cardinality :db.cardinality/one
 :db.install/_attribute :db.part/db})

 Each call to: (make-column-schema #db/id[:db.part/db] :results/subject
 :db.type/string)

 The value of #db/id[:db.part/db] is the different, as expected.

 Now I thought that I understood #db/id[:db.part/db] (call to a Java
 constructor) but obviously my understanding is flawed as I would expect both
 of these functions to produce the same thing, but they don't so there's
 obviously some gap in my understanding.

 Help?

 --
 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clojure@googlegroups.com
 Note that posts from new members are moderated - please be patient with your
 first post.
 To unsubscribe from this group, send email to
 clojure+unsubscr...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to the Google Groups
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an
 email to clojure+unsubscr...@googlegroups.com.
 For more options, visit https://groups.google.com/groups/opt_out.



-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.




Re: datomic question

2013-03-03 Thread edward
Okay, I think I understand that.

Does that mean this code could never work as intended in a Clojure program, 
only at the repl (which seems a bit of a limitation) or is there a way to 
make it work as intended, generating a different id each time? Or is the 
whole approach taken in this code flawed?

On Sunday, 3 March 2013 21:59:45 UTC, Michał Marczyk wrote:

 #db/id ... is a tagged literal. It gets read in as an id object with 
 some integer inside. The way this happens is that the reader looks up 
 a data reader function associated with the symbol db/id in the map 
 held by the var *data-readers* and passes to it the result of parsing 
 the rest of the literal (a vector holding the keyword :db.part/db in 
 this case). Importantly, this function is not pure and the integer it 
 uses will be different on each invocation. (Given this form of the 
 #db/id literal; you can also specify a particular number yourself -- 
 #db/id [:db.part/db some-number-here].) 

 In any case, once the reader reads in your code including some 
 particular id, the compiler will compile the result preserving the 
 particular values it sees, so it will embed code to construct *exactly 
 this* id in the compiled output. Thus you end up with a particular id 
 hardwired into the first version of your function. 

 With the second version, if you invoke it multiple times at the REPL, 
 you ask the reader for a new id at each invocation, so it works as you 
 expect. If instead you were to use it inside a function like so: 

 (defn foo [] 
   (make-column-schema #db/id [:db.part/db] :results/subject 
 :db.type/string)), 

 then again the same id would be used for every (foo) call. 

 Cheers, 
 Michał 


 On 3 March 2013 21:58,  edw...@kenworthy.info javascript: wrote: 
  So, I am studying a piece of code from the web. I've dissected most of 
 it 
  and am in the process of re-factoring it. 
  
  What I don't understand is why one version works and the other doesn't. 
  
  So for both: 
  
  (ns gcse-results.core (:use [datomic.api :only [q db] :as d]) (:use 
  quil.core)) 
  
  This doesn't work: 
  
  (defn make-column-schema [db-ident db-type] 
  {:db/id #db/id[:db.part/db] 
  :db/ident db-ident 
  :db/valueType db-type 
  :db/cardinality :db.cardinality/one 
  :db.install/_attribute :db.part/db}) 
  
  Each call to: 
  
  (make-column-schema :results/subject :db.type/string) 
  
  The value of #db/id[:db.part/db] is the same. 
  
  And this works: 
  
  (defn make-column-schema [db-id db-ident db-type] 
  {:db/id db-id 
  :db/ident db-ident 
  :db/valueType db-type 
  :db/cardinality :db.cardinality/one 
  :db.install/_attribute :db.part/db}) 
  
  Each call to: (make-column-schema #db/id[:db.part/db] :results/subject 
  :db.type/string) 
  
  The value of #db/id[:db.part/db] is the different, as expected. 
  
  Now I thought that I understood #db/id[:db.part/db] (call to a Java 
  constructor) but obviously my understanding is flawed as I would expect 
 both 
  of these functions to produce the same thing, but they don't so there's 
  obviously some gap in my understanding. 
  
  Help? 
  
  -- 
  -- 
  You received this message because you are subscribed to the Google 
  Groups Clojure group. 
  To post to this group, send email to clo...@googlegroups.comjavascript: 
  Note that posts from new members are moderated - please be patient with 
 your 
  first post. 
  To unsubscribe from this group, send email to 
  clojure+u...@googlegroups.com javascript: 
  For more options, visit this group at 
  http://groups.google.com/group/clojure?hl=en 
  --- 
  You received this message because you are subscribed to the Google 
 Groups 
  Clojure group. 
  To unsubscribe from this group and stop receiving emails from it, send 
 an 
  email to clojure+u...@googlegroups.com javascript:. 
  For more options, visit https://groups.google.com/groups/opt_out. 
  
  


-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.




Re: datomic question

2013-03-03 Thread Jonas
Hi

You can use the tempid 
(http://docs.datomic.com/clojure/index.html#datomic.api/tempid) function to 
generate new temporary ids.

Jonas

On Monday, March 4, 2013 8:50:56 AM UTC+2, edw...@kenworthy.info wrote:

 Okay, I think I understand that.

 Does that mean this code could never work as intended in a Clojure 
 program, only at the repl (which seems a bit of a limitation) or is there a 
 way to make it work as intended, generating a different id each time? Or is 
 the whole approach taken in this code flawed?

 On Sunday, 3 March 2013 21:59:45 UTC, Michał Marczyk wrote:

 #db/id ... is a tagged literal. It gets read in as an id object with 
 some integer inside. The way this happens is that the reader looks up 
 a data reader function associated with the symbol db/id in the map 
 held by the var *data-readers* and passes to it the result of parsing 
 the rest of the literal (a vector holding the keyword :db.part/db in 
 this case). Importantly, this function is not pure and the integer it 
 uses will be different on each invocation. (Given this form of the 
 #db/id literal; you can also specify a particular number yourself -- 
 #db/id [:db.part/db some-number-here].) 

 In any case, once the reader reads in your code including some 
 particular id, the compiler will compile the result preserving the 
 particular values it sees, so it will embed code to construct *exactly 
 this* id in the compiled output. Thus you end up with a particular id 
 hardwired into the first version of your function. 

 With the second version, if you invoke it multiple times at the REPL, 
 you ask the reader for a new id at each invocation, so it works as you 
 expect. If instead you were to use it inside a function like so: 

 (defn foo [] 
   (make-column-schema #db/id [:db.part/db] :results/subject 
 :db.type/string)), 

 then again the same id would be used for every (foo) call. 

 Cheers, 
 Michał 


 On 3 March 2013 21:58,  edw...@kenworthy.info wrote: 
  So, I am studying a piece of code from the web. I've dissected most of 
 it 
  and am in the process of re-factoring it. 
  
  What I don't understand is why one version works and the other doesn't. 
  
  So for both: 
  
  (ns gcse-results.core (:use [datomic.api :only [q db] :as d]) (:use 
  quil.core)) 
  
  This doesn't work: 
  
  (defn make-column-schema [db-ident db-type] 
  {:db/id #db/id[:db.part/db] 
  :db/ident db-ident 
  :db/valueType db-type 
  :db/cardinality :db.cardinality/one 
  :db.install/_attribute :db.part/db}) 
  
  Each call to: 
  
  (make-column-schema :results/subject :db.type/string) 
  
  The value of #db/id[:db.part/db] is the same. 
  
  And this works: 
  
  (defn make-column-schema [db-id db-ident db-type] 
  {:db/id db-id 
  :db/ident db-ident 
  :db/valueType db-type 
  :db/cardinality :db.cardinality/one 
  :db.install/_attribute :db.part/db}) 
  
  Each call to: (make-column-schema #db/id[:db.part/db] :results/subject 
  :db.type/string) 
  
  The value of #db/id[:db.part/db] is the different, as expected. 
  
  Now I thought that I understood #db/id[:db.part/db] (call to a Java 
  constructor) but obviously my understanding is flawed as I would expect 
 both 
  of these functions to produce the same thing, but they don't so there's 
  obviously some gap in my understanding. 
  
  Help? 
  
  -- 
  -- 
  You received this message because you are subscribed to the Google 
  Groups Clojure group. 
  To post to this group, send email to clo...@googlegroups.com 
  Note that posts from new members are moderated - please be patient with 
 your 
  first post. 
  To unsubscribe from this group, send email to 
  clojure+u...@googlegroups.com 
  For more options, visit this group at 
  http://groups.google.com/group/clojure?hl=en 
  --- 
  You received this message because you are subscribed to the Google 
 Groups 
  Clojure group. 
  To unsubscribe from this group and stop receiving emails from it, send 
 an 
  email to clojure+u...@googlegroups.com. 
  For more options, visit https://groups.google.com/groups/opt_out. 
  
  



-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.