APintex, Ainda não tinha pensado nisso mas é bem verdade.
Eu mudei para o OS X à 2 anos e digo-te é sem V de volta. Todos os portáteis baratos ou caros que passam pelas minhas mãos não chegam ao fim da garantia e este é impecável. Nada a apontar. De tal forma que após acabar a garantia, investi para duplicar a RAM e troquei o disco por um SSD e com garantia da Apple. Digo-te que valeu cada cêntimo principalmente para o FB que abusa da máquina. Por um lado gostaria de saír do FB. É um IDE preso no tempo :( mas por outro lado serve o seu propósito e pelo que sondei, os outros não estão à altura. Eu uso o MySQL em paralelo com o SQL Server à uns anos. Ao fim de algum tempo de conheceres bem os motores, consegues fazer SQL quase 100% compatível sem um ORM (principalmente se usares SQL Server 2012+). Todos os projectos que faço, faço logo compatíveis com esses 2 motores. Para reports (que nenhum dev gosta) para AIR recomendo o único que conheço: Stimulsoft mas é client-side. Podes usar uma app AIR via linha de comandos no servidor para gerar reports como workaround se precisares de reports no lado do servidor com PHP. Têm um solução ASP.NET para quem usar este backend sem workarounds. Já disse no forum que se fizeram um solução HTML5 (puro) estou disposto a pagar em avanço. Dizem que é algo que andam a pensar :) 2014-09-04 17:17 GMT+01:00 APintex Gmail <[email protected]>: > 2014 foi e está a ser um ano de mudanças... > Passei do Windows para o OS X, quero passar do Flash Builder para o > IntelliJ IDEA (ainda não tive coragem) > Estou a refazer um projecto de .Net para AIR, de MSSQL para MySQL e > webservices feitos em .Net para PHP. > No meio disto tudo o que mais me custa são os reports (uma seca para mim > desde sempre) > > António Pinto > [email protected] > > > > No dia 04/09/2014, às 16:58, Hugo Ferreira <[email protected]> > escreveu: > > É como eu. Na realidade acredito que a maioria esteja no mesmo barco. Para > coisas a sério ainda não. > Quem já trabalha à anos com Objective-C, irá continuar mesmo após o Swift > se tornar uma realidade viável. > > Terminei o meu primeiro projecto HTML5 e correu muito bem. No final > demorei muito menos tempo do que previa e já tenho agora uma base para > fazer o próximo mais rapidamente. > > Quando houver tempo irei recriar um projecto em Flex com HTML5 e mais > tarde outro (se isto algum dia vier a acontecer) e depois disso acho que > não voltarei a usar o Flash ! > > O AIR vou continuar a usar e abusar e também muito código nativo com > Android. > > Também acho que o Swift será uma realidade para mim só para o ano que vem ! > > > 2014-09-04 16:48 GMT+01:00 Apintex <[email protected]>: > >> Hugo, para já é pura curiosidade no Swift. Instalei o Xcode 6 beta e nem >> o abri. :( >> Vou vendo alguns exemplos para ir aprendendo alguma coisa e partilho com >> vocês os que acho importantes. >> Estou a terminar um projecto (MoneyEX Pro) e só no início do próximo ano >> começarei a trabalhar com o Swift. >> >> Att, >> >> António Pinto >> >> No dia 04/09/2014, às 16:10, Hugo Ferreira <[email protected]> >> escreveu: >> >> APintex, >> >> Acabei à pouco tempo de ler 2 bons livros de desenvolvimento Android. >> Já desenvolvi diversas ANE's para Android e já me sinto suficientemente >> confortável para desenvolver qualquer app para Android ou mesmo ANE. >> >> Em breve gostaria de entrar no desenvolvimento nativo para iOS (tanto >> apps como ANE's) e aqui ficam algumas dúvidas: >> 1. Não faz sentido nesta altura do campeonato investigar em Objective-C >> (thank you god); >> 2. Será que não vale a pena esperar por um bom livro que seja uma >> compilação do desenvolvimento Swift (de preferência em PT). Ainda não vi >> nenhum na Fnac; >> 3. Será que irá ser possível desenvolver ANE's com swift. Penso que aqui >> a única coisa que falta é a lib que actualmente é para Objective-C (para >> alguém transcrever tem de saber bem Objective-C) ou será possível usar a >> actual ? >> >> As minhas expectativas são: >> - Dentro de 1 ano o iOS8 tenha mais de 80% de market share para valer a >> pena; >> - Existam bons livros e exemplos; >> - Exista um lib para Swift (a Adobe tem de fazer) ou ser possível usar a >> actual (não sei); >> - Exista uma framework para Bluetooth LE (para mim é importante) tal como >> já existe com Objective-C ou se possa usar as actuais. >> >> >> >> 2014-09-04 15:58 GMT+01:00 APintex Gmail <[email protected]>: >> >>> >>> António Pinto >>> [email protected] >>> >>> >>> >>> http://realm.io/news/swift-enums-pattern-matching-generics/ >>> >>> Sign up to be notified of future videos >>> >>> We won't email you for any other reason, ever. >>> ------------------------------ >>> Enums (0:40) >>> >>> Enums are a kind of abstraction that allow you to give a variable one >>> value among several related values. For example, when building a state >>> machine you could have an enum that describes the state of an object from a >>> set number of states. There are three types of enums in Swift. >>> Basic Enum (1:12) >>> >>> The most basic Swift enum simply has a bunch of cases and is declared >>> using the enum key word. In this example, the enum is called Direction and >>> can only be one of the four provided cases. To declare an enum, you use the >>> enum name, followed by a dot and then one of the possible values. Unlike in >>> Objective-C or C, enums are not typedefs of aliases for integers. >>> >>> enum Direction { >>> case North >>> case South >>> case East >>> case West } >>> let myDirection = Direction.North >>> >>> Raw Value Enum (2:00) >>> >>> The second type of Swift enum is a "raw value" enum, which is the same >>> as the basic enum but has additional raw values associated with each case. >>> In this enum Title, each case has an associated string that is the name for >>> the title. Important to note is that the raw value and the enum itself are >>> not interchangeable. The toRaw and fromRaw methods help to go between the >>> value and the enum. >>> >>> enum Title : String { >>> case CEO = "Chief Executive Officer" >>> case CTO = "Chief Technical Officer" >>> case CFO = "Chief Financial Officer"} >>> let myTitle = Title.CEO let myString : String = Title.CEO.toRaw() let >>> anotherTitle : Title = >>> Title.fromRaw("Chief Executive Officer")! >>> >>> For integer type raw enums, integer numbering remains implicit if you do >>> not specify values. Swift automatically counts up from the last provided >>> explicit value. This can be seen in the following example: >>> >>> enum Planet : Int { >>> case Mercury = 1 >>> case Venus, Earth, Mars // 2, 3, 4 >>> case Jupiter = 100 >>> case Saturn, Uranus, Neptune // 101, 102, 103 } >>> >>> Associated Value Enum (3:52) >>> >>> The third type of enum is one with associated values. Each case in the >>> enum can carry associated data. In this example from the Swift book, the >>> bar code enum allows you to associate different QR codes with different >>> strings. >>> >>> enum Barcode { >>> case UPCA(sys: Int, data: Int, check: Int) >>> case QRCode(String) } >>> let myUPC = >>> Barcode.UPCA(sys: 0, data: 27917_01919, check: 2) let myQRCode = >>> Barcode.QRCode("http://example.com") >>> >>> Associated values are especially useful in handling JSON, because arrays >>> and dictionaries are actually types. Thus, you can create an enum to >>> represent a JSON structure as a tree, with JSON nodes wrapping different >>> types. >>> >>> enum JSONNode { >>> case NullNode >>> case StringNode(String) >>> case NumberNode(Float) >>> case BoolNode(Bool) >>> case ArrayNode([JSONNode]) >>> case ObjectNode([String:JSONNode]) } >>> let x : JSONNode = .ArrayNode( >>> [.NumberNode(10.0), >>> .StringNode("hello"), >>> .BoolNode(false)]) >>> >>> Switch Statements (Pattern Matching) (6:17) >>> >>> Switch statements is where most of the pattern matching functionality in >>> Swift comes from. A basic switch statement looks very similar to an >>> Objective-C switch statement, where there is a clause followed by cases. >>> Two things to note: Swift switches don't have breaks, so for old style >>> fallthrough behaviour, your code must have an explicit use of the keyword >>> fallthrough. Switch statements must also be comprehensive, so default cases >>> are required, which may help prevent errors. >>> >>> let value = 10switch value { case 10: println("ten") case 20: >>> println("twenty") case 30: println("thirty") default: println("another >>> number") } >>> >>> Ranges (8:35) >>> >>> In Swift, you can also pattern match on anything that's comparable. You >>> can even match strings now to a case (and printout emojis for a fun parlor >>> trick!). Anything that can be compared with the double equals operator can >>> be matched. Swift also allows matching on ranges, where ranges can be the >>> pattern inside a switch state. >>> >>> let v: UInt = 10switch v { case 0...9: println("Single digit") case >>> 10...99: println("Double digits") case 100...999: println("Triple digits") >>> default: println("4 or more digits") } >>> >>> Tuples (9:00) >>> >>> Tuples are composite data types - they contain multiple elements that >>> can all be of different types. A tuple is then represented by the types of >>> its elements. In this tuple-based switch statement, a tuple is the input. >>> Each element in the pattern tuple is actually a sub-pattern, so you can >>> match against patterns in each element. The underscore represents a "I >>> don't care" value. In this example, the last case functions as a default >>> because the (_, _) says the same thing as a default - none of the other >>> cases match, and we don't care about other possible values. >>> >>> let person = ("Helen", 25) switch person { case ("Helen", let age): >>> println("Your name is Helen, and you are \(age)" + " years old") case (_, >>> 13...19): >>> println("You are a teenager") case ("Bob", _): >>> println("You are not a teenager, but your name" + " is Bob.") case (_, _): >>> println("no comment") } >>> >>> Binding in Cases (10:56) >>> >>> If you have case statements, there may be associated data that needs to >>> be used in the case statement body. The let binding is how you can do that. >>> The first two cases in this example take the tuple elements and create the >>> bindings X and Y to represent those elements. >>> >>> let myTuple = ("abcd", 1234) switch myTuple { case let (x, y): >>> "The string in 'x' is \(x); " + "the integer in 'y' is \(y)"case (let x, >>> let y): >>> "Another way to do the exact same thing"case (_, let y): >>> "We don't care about the string in 'x', " + "but the integer in 'y' is >>> \(y)"} >>> >>> Enums (12:22) >>> >>> You can also switch on enums, but for enums with values wrapped inside, >>> switch statements are the only way you can access those values. The >>> following switch statement uses let to bind each case and use the value. >>> >>> enum ParseResult { >>> case NumericValue(Int) >>> case Error(String) } >>> let a = ParseResult.NumericValue(1) switch a { case let .NumericValue(v): >>> "Success; numeric value is \(v)"case .Error(let err): >>> "Failed; error message is \(err)"} >>> >>> Types (13:20) >>> >>> The main type of switch is the type/sub-class pattern. If your switch >>> conditional in this clause is a class, then class will have sub- or >>> superclasses. In this example, the UIView is matched against the different >>> possible types of views: UIImageView, UILabel, and UITableView. The "as" >>> keyword differs from the "is" keyword in that "as" allows you to use the >>> let binding and do something with myView, while "is" is used simply to >>> check the type. >>> >>> let myView : UIView = getView() switch myView { case is UIImageView: >>> println("It's an image view")case let lbl as UILabel: >>> println("It's a label, with text \(lbl.text)") case let tv as UITableView: >>> println("It's a table view, with"+ " \(tv.numberOfSections()) sections") >>> default: >>> println("It's some other type of view") } >>> >>> where clause (14:33) >>> >>> Another important thing about switch statements is the where cause. This >>> clause can be added to any case and acts as a boolean expression that >>> returns true or false. The case is then taken only if this where clause >>> returns true. This switch example relies not on pattern matching but >>> instead on these where clauses, following through with the case if myView >>> is of a certain size or other characteristic. >>> >>> let myView : UIView = getView() switch myView { case _ where >>> myView.frame.size.height < 50: >>> println("Your view is shorter than 50 units") case _ where >>> myView.frame.size.width > 20: >>> println("Your view is at least 50 units tall," + " and is more than 20 >>> units wide") case _ where >>> myView.backgroundColor == UIColor.greenColor(): >>> println("Your view is at least 50 units tall," + " at most 20 units wide, >>> and is green.") default: >>> println("I can't describe your view.") } >>> >>> Expression Operator (15:28) >>> >>> A final important feature in Swift is the expression operator. >>> >>> func ~=(pattern: Type1, value: Type2) -> Bool >>> >>> This operator takes the pattern and the value, and then uses pattern >>> matching to return true or false. It can be overloaded as well to implement >>> custom matching behaviour. The following piece of code is Swift pseudo-code >>> to demonstrate what you could build. In an array four elements long, you >>> could create cases that matched any combination of the elements. >>> >>> let myArray = [1, 2, 4, 3]switch myArray { case [..., 0, 0, 0]: >>> doSomething()case [4, ...]: >>> doSomething() case [_, 2, _, 4]: >>> doSomething() case [_, _, 3, _]: >>> doSomething() case [_, _, _, 3]: >>> doSomething() default: >>> doDefault() } >>> >>> Expression Patterns (17:42) >>> >>> The following extended example is a custom implementation of the pattern >>> match operator. This custom operator turns the elements of an array into >>> the enum values. >>> >>> enum WCEnum { >>> case Wildcard >>> case FromBeginning >>> case ToEnd >>> case Literal(Int) } >>> func ~=(pattern: [WCEnum], value: [Int]) -> Bool { >>> var ctr = 0 >>> for currentPattern in pattern { >>> if ctr >= value.count || ctr < 0 { return false } >>> let currentValue = value[ctr] >>> switch currentPattern { >>> case .Wildcard: ctr++ >>> case .FromBeginning where ctr == 0: >>> ctr = (value.count - pattern.count + 1) >>> case .FromBeginning: return false >>> case .ToEnd: return true >>> case .Literal(let v): >>> if v != currentValue { return false } >>> else { ctr++ } >>> } >>> } >>> return true} >>> >>> Protocols (21:06) >>> >>> In order to understand generics, you have to understand protocols, which >>> are something that existed in Objective-C as well. Protocols are basically >>> a contract that can define nothing at all or any number of methods and >>> properties. However, protocols can't have any implementation details - they >>> can only have method signatures and property names. MyProtocol in this code >>> defines just one property as requiring a getter and setter, as well as one >>> method. >>> >>> protocol MyProtocol { >>> var someProperty : Int { get set } >>> func barFunc (x: Int, y: Int) -> String} >>> >>> Types can conform to none, one, or multiple protocols. Protocols can >>> also inherit from other protocols, thereby getting all the parent >>> protocol's methods and properties. >>> Conformance (23:18) >>> >>> With protocols, you can make classes, structs, and enums conform to >>> them. By making a type conform to a protocol, you are telling the compiler >>> that your type will match the definitions set in the protocol. MyClass >>> conforms to MyProtocol in providing implementations that match. >>> >>> class MyClass { >>> // Nothing here... >>> // This won't compile!} >>> class MyClass : MyProtocol { >>> var myProperty : Int = 0 >>> // Property conformance >>> func barFunc (x: Int, y: Int) -> String { >>> return "\(x) + \(y) = \(x + y)" >>> } >>> var someProperty : Int { >>> get { >>> return myProperty >>> } >>> set { >>> myProperty = newValue >>> } >>> } } >>> >>> Uses (24:06) >>> >>> There are a few reasons you may want to use protocols. The first reason >>> is parent-child relationships, where you don't want all the children to >>> have a specific class of a parent. For example, UITableView comes with >>> Cocoa and is a list of objects that specifies the number and content of >>> cells. For the delegate to provide that information, it just has to >>> implement the protocol which has methods for the cells. This way, you can >>> avoid specifying the delegate as a sub-class of a class. >>> >>> A second major use for protocols can be seen in the Swift Standard >>> Library, where they add functionality to a type, piece by piece. Equatable, >>> LogicValue, and AbsoluteValuable are all protocols that are implemented by >>> different types in the library. The LogicValue protocol has a method that >>> takes an object and turns it into true or false, so if you create a custom >>> type and implement this protocol, you can use that type in an if >>> statement's clause. >>> >>> One final use for protocols is to allow different types to be described >>> by the same generic type parameter. For example, if you wanted to put >>> different types into an array, you could give the objects a protocol and >>> then declare the array with the protocol. You then have an array of >>> equatables and anything that conforms to the equatable in that array can be >>> added. >>> >>> protocol JSONType { } extension String : JSONType { } extension Float : >>> JSONType { } extension Bool : JSONType { } extension Array : JSONType { } >>> extension Dictionary : JSONType { } >>> let b : Array<JSONType> = [10.1, 10.2, "foo"] let a : Array<JSONType> = >>> [10.0, "bar", false, b] >>> >>> Generics (28:36) >>> >>> Generics did not exist in Objective-C. THey are basically the statically >>> typed languages' answer to the flexibility of dynamically typed languages. >>> Generics are used to allow you to use the same code for different types. >>> The type parameter allows you to do this generically. >>> >>> func swapItems<T>(inout this: T, inout that: T) { >>> let tempThis = this >>> this = that >>> that = tempThis } >>> >>> With generics, you can also enforce more constraints, as in the >>> following example. The ": Equatable" allows you to constrain T to any type >>> that conforms to Equatable, or is valid with the double equals operator. >>> >>> func firstAndLastAreEqual<T : Equatable> >>> (someArray: Array<T>) -> Bool { >>> let first = someArray[0] >>> let last = someArray[someArray.count - 1] >>> return first == last } >>> >>> You can also use generics for either functions or type declarations. >>> Type information is available at runtime, which is helpful. The compiler >>> can optimize by creating specific versions for each type that's being used >>> (like C++ templates), but it can also fall back to the generic >>> implementation. >>> Extended Example (33:56) >>> >>> In the extended example, the goal was to create a function that was >>> typesafe and could handle every case that involved the following types: >>> Array, Dictionary, SquareMatrix, TreeNode. The function was to take a >>> collection of one of the above types, take an array, and append the items >>> in that collection to the array. >>> >>> A protocol was defined to specify that a type can give back all of the >>> elements inside of it. You have containers that can implement >>> "AllElements". On a generic level, you might need to know the type of the >>> elements inside the collection, and so a wildcard is called "ElementType". >>> And so, you specify the element type when you implement the function >>> itself. >>> >>> protocol AllElements { >>> typealias ElementType >>> // Return an array containing all the objects >>> // in the collection >>> func allElements() -> Array<ElementType> } >>> >>> Another thing you can use is the NilLiteral protocol, the point of which >>> is to take nil and turn it into something equivalent to nil in that type. >>> For an int, it would return 0, or maybe for a string, it would return "". >>> In the following example, you would want it to return something of type >>> self. >>> >>> protocol NilLiteralConvertible { >>> class func convertFromNilLiteral() -> Self} >>> >>> Extensions then add methods, computed properties, and protocol >>> conformance to existing types. Array and SquareMatrix are both fairly >>> straightforward - you just return the arrays themselves. For the >>> Dictionary, you iterate through all the elements, create a buffer, and >>> return it with the elements inside. Finally, for the tree, you go through >>> the tree in a recursive traversal and again add the elements to a buffer. >>> >>> Put together, the final function appendToArray calls AllElements and >>> gives "a", which is an array with all the elements on the source. Then each >>> of those elements is just added to the array in "dest". This works because >>> the generic argument "T" has to implement AllElements, and U has been >>> constrained to the same type as T. The where clause is included in case you >>> want to do more than have this type implement one protocol. Before the >>> where, you declare type arguments, which can conform to either one or none >>> protocols. If you want T to conform to 2+ protocols, add a "where" clause >>> to constrain. You can then constrain any free type arguments you declared >>> earlier and any associated types associated with the type arguments via >>> protocols (e.g. T.SomeType). >>> >>> func appendToArray >>> <T: AllElements, U where U == T.ElementType> >>> (source: T, inout dest: Array<U>) { >>> >>> let a = source.allElements() >>> for element in a { >>> dest.append(element) >>> } } >>> var buffer = ["a", "b", "c"] appendToArray([1: "foo", 2: "bar"], &buffer) >>> >>> Now you've created five methods for this one process. In actuality, you >>> would have your containers implement Sequence and use a for-in loop to go >>> through all the elements. This requires knowledge of Generators, >>> EnumerateGenerators, and other material. >>> Q&A (46:05) >>> >>> *Q: In the extension example, are we extending all arrays of anything?* >>> Austin: Yes, which is why this is a bad idea in practice. You can't >>> actually say that you only want arrays with JSON type objects to also >>> implement JSON array, which is needed to ensure that you have valid JSON. >>> >>> *Q: Is the type T built-in? Where does it come from?* >>> Austin: T is actually coming from the declaration of array. If you >>> command-click an array in XCode, the declaration of the array shows that it >>> declares a generic argument T that has some constraints. >>> >>> *Q: Is there any kind of trace for generics and the way it works? Is it >>> traceable to an existing language or is it brand-new?* >>> Austin: I don't know the answer, but I'm sure there are precedents. >>> Generics in Swift kind of de-emphasize object oriented programming because >>> they're built more around protocols than around class hierarchies. You >>> might get a closer procedent if you looked at Haskell. >>> >>> *Q: What is the exclamation point used for?* >>> Austin: The exclamation mark is for optionals. Everything in Swift is >>> non-nilable by default, so if you want to set something to nil, it must be >>> declared as an optional. The question mark after the type signifies this. >>> Then, the exclamation mark, or bang, takes the value out of the optional so >>> you can use it. >>> >>> *Q: Is there something like value template parameters in Swift? Or >>> should we just type in, type template?* >>> Austin: I don't think so, I don't think Swift generics are as powerful. >>> >>> *Q: Can you explain let? It seemed like it would sometimes check the >>> case and othertimes it would set it to the constant.* >>> Austin: A let pattern kind of matches everything, but also takes a value >>> and puts it in the constant for later use. When we use "as", it both checks >>> the type and also puts it in the constant. >>> ------------------------------ >>> Sign up to be notified of future videos >>> >>> We won't email you for any other reason, ever. >>> >>> >>> -- >>> Recebeu esta mensagem porque subscreveu ao grupo "Mailing List da >>> Comunidade Portuguesa de Rich Internet Applications - www.riapt.org" do >>> Grupos do Google. >>> Para anular a subscrição deste grupo e parar de receber emails do mesmo, >>> envie um email para [email protected]. >>> Para publicar uma mensagem neste grupo, envie um email para >>> [email protected]. >>> Visite este grupo em http://groups.google.com/group/riapt. >>> Para mais opções, visite https://groups.google.com/d/optout. >>> >> >> >> -- >> Recebeu esta mensagem porque subscreveu ao grupo "Mailing List da >> Comunidade Portuguesa de Rich Internet Applications - www.riapt.org" do >> Grupos do Google. >> Para anular a subscrição deste grupo e parar de receber emails do mesmo, >> envie um email para [email protected]. >> Para publicar uma mensagem neste grupo, envie um email para >> [email protected]. >> Visite este grupo em http://groups.google.com/group/riapt. >> Para mais opções, visite https://groups.google.com/d/optout. >> >> >> -- >> Recebeu esta mensagem porque subscreveu ao grupo "Mailing List da >> Comunidade Portuguesa de Rich Internet Applications - www.riapt.org" do >> Grupos do Google. >> Para anular a subscrição deste grupo e parar de receber emails do mesmo, >> envie um email para [email protected]. >> Para publicar uma mensagem neste grupo, envie um email para >> [email protected]. >> Visite este grupo em http://groups.google.com/group/riapt. >> Para mais opções, visite https://groups.google.com/d/optout. >> > > > -- > Recebeu esta mensagem porque subscreveu ao grupo "Mailing List da > Comunidade Portuguesa de Rich Internet Applications - www.riapt.org" do > Grupos do Google. > Para anular a subscrição deste grupo e parar de receber emails do mesmo, > envie um email para [email protected]. > Para publicar uma mensagem neste grupo, envie um email para > [email protected]. > Visite este grupo em http://groups.google.com/group/riapt. > Para mais opções, visite https://groups.google.com/d/optout. > > > -- > Recebeu esta mensagem porque subscreveu ao grupo "Mailing List da > Comunidade Portuguesa de Rich Internet Applications - www.riapt.org" do > Grupos do Google. > Para anular a subscrição deste grupo e parar de receber emails do mesmo, > envie um email para [email protected]. > Para publicar uma mensagem neste grupo, envie um email para > [email protected]. > Visite este grupo em http://groups.google.com/group/riapt. > Para mais opções, visite https://groups.google.com/d/optout. > -- Recebeu esta mensagem porque está inscrito no grupo "Mailing List da Comunidade Portuguesa de Rich Internet Applications - www.riapt.org" dos Grupos do Google. Para anular a subscrição deste grupo e parar de receber emails do mesmo, envie um email para [email protected]. Para publicar uma mensagem neste grupo, envie um e-mail para [email protected]. Visite este grupo em http://groups.google.com/group/riapt. Para mais opções, consulte https://groups.google.com/d/optout.
