diff --git a/data/PR inline comments/.DS_Store b/data/PR inline comments/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/data/PR inline comments/.DS_Store differ diff --git a/data/PR inline comments/actionbarsherlock_sentiment_pr_inline_comments_joined.csv b/data/PR inline comments/actionbarsherlock_sentiment_pr_inline_comments_joined.csv new file mode 100644 index 0000000..8750c88 --- /dev/null +++ b/data/PR inline comments/actionbarsherlock_sentiment_pr_inline_comments_joined.csv @@ -0,0 +1,19 @@ +comment_id,polarity,text,created_at_gold,author_login,owner,repo,review_id,html_url,created_at_kaiaulu,updated_at,comment_user_login,author_association,file_path,start_line,line,original_start_line,original_line,position,diff_hunk,body,commit_id +2386669,1,"that would be great, thanks, can't find any documentation on this feature.""",2012-12-11 12:27:48,jberkel,JakeWharton,ActionBarSherlock,,https://github.com/JakeWharton/ActionBarSherlock/pull/736#discussion_r2386669,2012-12-11T23:27:48Z,2012-12-11T23:27:48Z,jberkel,NONE,library/src/com/actionbarsherlock/app/SherlockActivity.java,,22.0,,,11,"@@ -18,6 +19,7 @@ + import com.actionbarsherlock.view.MenuInflater; + import com.actionbarsherlock.view.MenuItem; + ++@TargetApi(11) ","that would be great, thanks, can't find any documentation on this feature. +",10a82cde65d4b063c5512b38a19652bbe9f32793 +2379700,0,"This is wrong since it works on API 7+""",2012-12-11 04:51:21,JakeWharton,JakeWharton,ActionBarSherlock,,https://github.com/JakeWharton/ActionBarSherlock/pull/736#discussion_r2379700,2012-12-11T15:51:21Z,2012-12-11T15:51:21Z,JakeWharton,OWNER,library/src/com/actionbarsherlock/app/SherlockActivity.java,,22.0,,,11,"@@ -18,6 +19,7 @@ + import com.actionbarsherlock.view.MenuInflater; + import com.actionbarsherlock.view.MenuItem; + ++@TargetApi(11) ","This is wrong since it works on API 7+ +",10a82cde65d4b063c5512b38a19652bbe9f32793 +2389775,1,"i build my project using maven so there is no ABS library folder per se (get recreated for each build) so this might not be applicable. thanks for your help anyway!""",2012-12-11 21:17:34,jberkel,JakeWharton,ActionBarSherlock,,https://github.com/JakeWharton/ActionBarSherlock/pull/736#discussion_r2389775,2012-12-12T08:17:34Z,2012-12-12T08:17:34Z,jberkel,NONE,library/src/com/actionbarsherlock/app/SherlockActivity.java,,22.0,,,11,"@@ -18,6 +19,7 @@ + import com.actionbarsherlock.view.MenuInflater; + import com.actionbarsherlock.view.MenuItem; + ++@TargetApi(11) ","i build my project using maven so there is no ABS library folder per se (get recreated for each build) so this might not be applicable. thanks for your help anyway! +",10a82cde65d4b063c5512b38a19652bbe9f32793 diff --git a/data/PR inline comments/akka_sentiment_pr_inline_comments_joined.csv b/data/PR inline comments/akka_sentiment_pr_inline_comments_joined.csv new file mode 100644 index 0000000..75a9680 --- /dev/null +++ b/data/PR inline comments/akka_sentiment_pr_inline_comments_joined.csv @@ -0,0 +1,6514 @@ +comment_id,polarity,text,created_at_gold,author_login,owner,repo,review_id,html_url,created_at_kaiaulu,updated_at,comment_user_login,author_association,file_path,start_line,line,original_start_line,original_line,position,diff_hunk,body,commit_id +392938,1,"hmm mine looks like rvm ree@diaspora :P""",2012-01-27 07:40:28,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/275#discussion_r392938,2012-01-27T18:40:28Z,2012-01-30T10:58:22Z,viktorklang,CONTRIBUTOR,akka-remote/src/main/scala/akka/remote/netty/Client.scala,,346.0,,,346,"@@ -0,0 +1,346 @@ ++/** ++ * Copyright (C) 2009-2011 Typesafe Inc. ++ */ ++package akka.remote.netty ++ ++import java.net.InetSocketAddress ++import org.jboss.netty.util.HashedWheelTimer ++import org.jboss.netty.bootstrap.ClientBootstrap ++import org.jboss.netty.channel.group.DefaultChannelGroup ++import org.jboss.netty.channel.{ ChannelHandler, StaticChannelPipeline, SimpleChannelUpstreamHandler, MessageEvent, ExceptionEvent, ChannelStateEvent, ChannelPipelineFactory, ChannelPipeline, ChannelHandlerContext, ChannelFuture, Channel } ++import org.jboss.netty.handler.codec.frame.{ LengthFieldPrepender, LengthFieldBasedFrameDecoder } ++import org.jboss.netty.handler.execution.ExecutionHandler ++import org.jboss.netty.handler.timeout.{ ReadTimeoutHandler, ReadTimeoutException } ++import akka.remote.RemoteProtocol.{ RemoteControlProtocol, CommandType, AkkaRemoteProtocol } ++import akka.remote.{ RemoteProtocol, RemoteMessage, RemoteLifeCycleEvent, RemoteClientStarted, RemoteClientShutdown, RemoteClientException, RemoteClientError, RemoteClientDisconnected, RemoteClientConnected } ++import akka.actor.{ simpleName, Address } ++import akka.AkkaException ++import akka.event.Logging ++import akka.util.Switch ++import akka.actor.ActorRef ++import org.jboss.netty.channel.ChannelFutureListener ++import akka.remote.RemoteClientWriteFailed ++import java.net.InetAddress ++import org.jboss.netty.util.TimerTask ++import org.jboss.netty.util.Timeout ++import java.util.concurrent.TimeUnit ++ ++class RemoteClientMessageBufferException(message: String, cause: Throwable) extends AkkaException(message, cause) { ++ def this(msg: String) = this(msg, null) ++} ++ ++/** ++ * This is the abstract baseclass for netty remote clients, currently there's only an ++ * ActiveRemoteClient, but others could be feasible, like a PassiveRemoteClient that ++ * reuses an already established connection. ++ */ ++abstract class RemoteClient private[akka] ( ++ val netty: NettyRemoteTransport, ++ val remoteAddress: Address) { ++ ++ val log = Logging(netty.system, ""RemoteClient"") ++ ++ val name = simpleName(this) + ""@"" + remoteAddress ++ ++ private[remote] val runSwitch = new Switch() ++ ++ private[remote] def isRunning = runSwitch.isOn ++ ++ protected def currentChannel: Channel ++ ++ def connect(reconnectIfAlreadyConnected: Boolean = false): Boolean ++ ++ def shutdown(): Boolean ++ ++ def isBoundTo(address: Address): Boolean = remoteAddress == address ++ ++ /** ++ * Converts the message to the wireprotocol and sends the message across the wire ++ */ ++ def send(message: Any, senderOption: Option[ActorRef], recipient: ActorRef): Unit = if (isRunning) { ++ if (netty.remoteSettings.LogSend) log.debug(""Sending message {} from {} to {}"", message, senderOption, recipient) ++ send((message, senderOption, recipient)) ++ } else { ++ val exception = new RemoteClientException(""RemoteModule client is not running, make sure you have invoked 'RemoteClient.connect()' before using it."", netty, remoteAddress) ++ netty.notifyListeners(RemoteClientError(exception, netty, remoteAddress)) ++ throw exception ++ } ++ ++ /** ++ * Sends the message across the wire ++ */ ++ private def send(request: (Any, Option[ActorRef], ActorRef)): Unit = { ++ try { ++ val channel = currentChannel ++ val f = channel.write(request) ++ f.addListener( ++ new ChannelFutureListener { ++ def operationComplete(future: ChannelFuture) { ++ if (future.isCancelled || !future.isSuccess) { ++ netty.notifyListeners(RemoteClientWriteFailed(request, future.getCause, netty, remoteAddress)) ++ } ++ } ++ }) ++ // Check if we should back off ++ if (!channel.isWritable) { ++ val backoff = netty.settings.BackoffTimeout ++ if (backoff.length > 0 && !f.await(backoff.length, backoff.unit)) f.cancel() //Waited as long as we could, now back off ++ } ++ } catch { ++ case e: Exception ⇒ netty.notifyListeners(RemoteClientError(e, netty, remoteAddress)) ++ } ++ } ++ ++ override def toString = name ++} ++ ++/** ++ * RemoteClient represents a connection to an Akka node. Is used to send messages to remote actors on the node. ++ */ ++class ActiveRemoteClient private[akka] ( ++ netty: NettyRemoteTransport, ++ remoteAddress: Address, ++ localAddress: Address) ++ extends RemoteClient(netty, remoteAddress) { ++ ++ import netty.settings ++ ++ //TODO rewrite to a wrapper object (minimize volatile access and maximize encapsulation) ++ @volatile ++ private var bootstrap: ClientBootstrap = _ ++ @volatile ++ private var connection: ChannelFuture = _ ++ @volatile ++ private[remote] var openChannels: DefaultChannelGroup = _ ++ @volatile ++ private var executionHandler: ExecutionHandler = _ ++ ++ @volatile ++ private var reconnectionTimeWindowStart = 0L ++ ++ def notifyListeners(msg: RemoteLifeCycleEvent): Unit = netty.notifyListeners(msg) ++ ++ def currentChannel = connection.getChannel ++ ++ /** ++ * Connect to remote server. ++ */ ++ def connect(reconnectIfAlreadyConnected: Boolean = false): Boolean = { ++ ++ def sendSecureCookie(connection: ChannelFuture) { ++ val handshake = RemoteControlProtocol.newBuilder.setCommandType(CommandType.CONNECT) ++ if (settings.SecureCookie.nonEmpty) handshake.setCookie(settings.SecureCookie.get) ++ handshake.setOrigin(RemoteProtocol.AddressProtocol.newBuilder ++ .setSystem(localAddress.system) ++ .setHostname(localAddress.host.get) ++ .setPort(localAddress.port.get) ++ .build) ++ connection.getChannel.write(netty.createControlEnvelope(handshake.build)) ++ } ++ ++ def attemptReconnect(): Boolean = { ++ val remoteIP = InetAddress.getByName(remoteAddress.host.get) ++ log.debug(""Remote client reconnecting to [{}|{}]"", remoteAddress, remoteIP) ++ connection = bootstrap.connect(new InetSocketAddress(remoteIP, remoteAddress.port.get)) ++ openChannels.add(connection.awaitUninterruptibly.getChannel) // Wait until the connection attempt succeeds or fails. ++ ++ if (!connection.isSuccess) { ++ notifyListeners(RemoteClientError(connection.getCause, netty, remoteAddress)) ++ false ++ } else { ++ sendSecureCookie(connection) ++ true ++ } ++ } ++ ++ runSwitch switchOn { ++ openChannels = new DefaultDisposableChannelGroup(classOf[RemoteClient].getName) ++ ++ executionHandler = new ExecutionHandler(netty.executor) ++ ++ bootstrap = new ClientBootstrap(netty.clientChannelFactory) ++ bootstrap.setPipelineFactory(new ActiveRemoteClientPipelineFactory(name, bootstrap, executionHandler, remoteAddress, this)) ++ bootstrap.setOption(""tcpNoDelay"", true) ++ bootstrap.setOption(""keepAlive"", true) ++ bootstrap.setOption(""connectTimeoutMillis"", settings.ConnectionTimeout.toMillis) ++ ++ val remoteIP = InetAddress.getByName(remoteAddress.host.get) ++ log.debug(""Starting remote client connection to [{}|{}]"", remoteAddress, remoteIP) ++ ++ connection = bootstrap.connect(new InetSocketAddress(remoteIP, remoteAddress.port.get)) ++ ++ openChannels.add(connection.awaitUninterruptibly.getChannel) // Wait until the connection attempt succeeds or fails. ++ ++ if (!connection.isSuccess) { ++ notifyListeners(RemoteClientError(connection.getCause, netty, remoteAddress)) ++ false ++ } else { ++ sendSecureCookie(connection) ++ notifyListeners(RemoteClientStarted(netty, remoteAddress)) ++ true ++ } ++ } match { ++ case true ⇒ true ++ case false if reconnectIfAlreadyConnected ⇒ ++ connection.getChannel.close() ++ openChannels.remove(connection.getChannel) ++ ++ log.debug(""Remote client reconnecting to [{}]"", remoteAddress) ++ attemptReconnect() ++ ++ case false ⇒ false ++ } ++ } ++ ++ // Please note that this method does _not_ remove the ARC from the NettyRemoteClientModule's map of clients ++ def shutdown() = runSwitch switchOff { ++ log.debug(""Shutting down remote client [{}]"", name) ++ ++ notifyListeners(RemoteClientShutdown(netty, remoteAddress)) ++ try { ++ if ((connection ne null) && (connection.getChannel ne null)) ++ connection.getChannel.close() ++ } finally { ++ try { ++ if (openChannels ne null) openChannels.close.awaitUninterruptibly() ++ } finally { ++ connection = null ++ executionHandler = null ++ } ++ } ++ ++ log.debug(""[{}] has been shut down"", name) ++ } ++ ++ private[akka] def isWithinReconnectionTimeWindow: Boolean = { ++ if (reconnectionTimeWindowStart == 0L) { ++ reconnectionTimeWindowStart = System.currentTimeMillis ++ true ++ } else { ++ val timeLeft = (settings.ReconnectionTimeWindow.toMillis - (System.currentTimeMillis - reconnectionTimeWindowStart)) > 0 ++ if (timeLeft) ++ log.info(""Will try to reconnect to remote server for another [{}] milliseconds"", timeLeft) ++ ++ timeLeft ++ } ++ } ++ ++ private[akka] def resetReconnectionTimeWindow = reconnectionTimeWindowStart = 0L ++} ++ ++@ChannelHandler.Sharable ++class ActiveRemoteClientHandler( ++ val name: String, ++ val bootstrap: ClientBootstrap, ++ val remoteAddress: Address, ++ val timer: HashedWheelTimer, ++ val client: ActiveRemoteClient) ++ extends SimpleChannelUpstreamHandler { ++ ++ def runOnceNow(thunk: ⇒ Unit): Unit = timer.newTimeout(new TimerTask() { ++ def run(timeout: Timeout) = try { thunk } finally { timeout.cancel() } ++ }, 0, TimeUnit.MILLISECONDS) ++ ++ override def messageReceived(ctx: ChannelHandlerContext, event: MessageEvent) { ++ try { ++ event.getMessage match { ++ case arp: AkkaRemoteProtocol if arp.hasInstruction ⇒ ++ val rcp = arp.getInstruction ++ rcp.getCommandType match { ++ case CommandType.SHUTDOWN ⇒ runOnceNow { client.netty.shutdownClientConnection(remoteAddress) } ++ case _ ⇒ //Ignore others ++ } ++ ++ case arp: AkkaRemoteProtocol if arp.hasMessage ⇒ ++ client.netty.receiveMessage(new RemoteMessage(arp.getMessage, client.netty.system)) ++ ++ case other ⇒ ++ throw new RemoteClientException(""Unknown message received in remote client handler: "" + other, client.netty, client.remoteAddress) ++ } ++ } catch { ++ case e: Exception ⇒ client.notifyListeners(RemoteClientError(e, client.netty, client.remoteAddress)) ++ } ++ } ++ ++ override def channelClosed(ctx: ChannelHandlerContext, event: ChannelStateEvent) = client.runSwitch ifOn { ++ if (client.isWithinReconnectionTimeWindow) { ++ timer.newTimeout(new TimerTask() { ++ def run(timeout: Timeout) = ++ if (client.isRunning) { ++ client.openChannels.remove(event.getChannel) ++ client.connect(reconnectIfAlreadyConnected = true) ++ } ++ }, client.netty.settings.ReconnectDelay.toMillis, TimeUnit.MILLISECONDS) ++ } else runOnceNow { ++ client.netty.shutdownClientConnection(remoteAddress) // spawn in another thread ++ } ++ } ++ ++ override def channelConnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = { ++ try { ++ client.notifyListeners(RemoteClientConnected(client.netty, client.remoteAddress)) ++ client.resetReconnectionTimeWindow ++ } catch { ++ case e: Exception ⇒ client.notifyListeners(RemoteClientError(e, client.netty, client.remoteAddress)) ++ } ++ } ++ ++ override def channelDisconnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = { ++ client.notifyListeners(RemoteClientDisconnected(client.netty, client.remoteAddress)) ++ } ++ ++ override def exceptionCaught(ctx: ChannelHandlerContext, event: ExceptionEvent) = { ++ val cause = event.getCause ++ if (cause ne null) { ++ client.notifyListeners(RemoteClientError(cause, client.netty, client.remoteAddress)) ++ cause match { ++ case e: ReadTimeoutException ⇒ ++ runOnceNow { ++ client.netty.shutdownClientConnection(remoteAddress) // spawn in another thread ++ } ++ case e: Exception ⇒ event.getChannel.close() ++ } ++ ++ } else client.notifyListeners(RemoteClientError(new Exception(""Unknown cause""), client.netty, client.remoteAddress)) ++ } ++} ++ ++class ActiveRemoteClientPipelineFactory( ++ name: String, ++ bootstrap: ClientBootstrap, ++ executionHandler: ExecutionHandler, ++ remoteAddress: Address, ++ client: ActiveRemoteClient) extends ChannelPipelineFactory { ++ ++ import client.netty.settings ++ ++ def getPipeline: ChannelPipeline = { ++ val timeout = new ReadTimeoutHandler(client.netty.timer, settings.ReadTimeout.length, settings.ReadTimeout.unit) ++ val lenDec = new LengthFieldBasedFrameDecoder(settings.MessageFrameSize, 0, 4, 0, 4) ++ val lenPrep = new LengthFieldPrepender(4) ++ val messageDec = new RemoteMessageDecoder ++ val messageEnc = new RemoteMessageEncoder(client.netty) ++ val remoteClient = new ActiveRemoteClientHandler(name, bootstrap, remoteAddress, client.netty.timer, client) ++ ++ new StaticChannelPipeline(timeout, lenDec, messageDec, lenPrep, messageEnc, executionHandler, remoteClient) ++ } ++} ++ ++class PassiveRemoteClient(val currentChannel: Channel, ++ netty: NettyRemoteTransport, ++ remoteAddress: Address) ++ extends RemoteClient(netty, remoteAddress) { ++ ++ def connect(reconnectIfAlreadyConnected: Boolean = false): Boolean = runSwitch switchOn { ++ netty.notifyListeners(RemoteClientStarted(netty, remoteAddress)) ++ log.debug(""Starting remote client connection to [{}]"", remoteAddress) ++ } ++ ++ def shutdown() = runSwitch switchOff { ++ log.debug(""Shutting down remote client [{}]"", name) ++ ++ netty.notifyListeners(RemoteClientShutdown(netty, remoteAddress)) ++ log.debug(""[{}] has been shut down"", name) ++ } ++}","Is anything of the file above changed? I don't like these sweeping changes :p +",4fb0858e557232e5f4a7e5b364d1697c0e21bdd1 +367173,0,"If you add features to the view, please always add a corresponding test to AbstractLayoutTest to make sure the same functionality is supported by all rendering engines. I will add this test now.""",2012-01-19 04:04:51,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/223#discussion_r367173,2012-01-19T15:04:51Z,2012-01-19T22:37:20Z,viktorklang,CONTRIBUTOR,akka-transactor/src/main/scala/akka/transactor/Coordinated.scala,,129.0,,,15,"@@ -125,7 +126,7 @@ class Coordinated(val message: Any, member: CommitBarrier.Member) { + * + * @throws CoordinatedTransactionException if the coordinated transaction fails. + */ +- def atomic[T](body: InTxn ⇒ T): T = { ++ def atomic[A](body: InTxn ⇒ A): A = {","A is much better than T +",eecb2a624745f1d3f45c4fd99f0b442c0390f606 +506731,0,"Because I needed a specific apply method to create the Node instance. Same signature as the generated one but different impl: def apply(name: String): Node = new Node(hash(name))""",2012-03-01 02:50:39,jboner,akka,akka,,https://github.com/akka/akka-core/pull/329#discussion_r506731,2012-03-01T13:50:39Z,2012-03-12T18:22:17Z,jboner,CONTRIBUTOR,akka-cluster/src/main/scala/akka/cluster/VectorClock.scala,,,,,1,"@@ -5,138 +5,199 @@ + package akka.cluster + + import akka.AkkaException ++import akka.event.Logging ++import akka.actor.ActorSystem ++ ++import System.{ currentTimeMillis ⇒ newTimestamp } ++import java.security.MessageDigest ++import java.util.concurrent.atomic.AtomicLong + + class VectorClockException(message: String) extends AkkaException(message) + + /** + * Trait to be extended by classes that wants to be versioned using a VectorClock. + */ +-trait Versioned { ++trait Versioned[T] { + def version: VectorClock ++ def +(node: VectorClock.Node): T + } + + /** + * Utility methods for comparing Versioned instances. + */ + object Versioned { +- def latestVersionOf[T <: Versioned](versioned1: T, versioned2: T): T = { +- (versioned1.version compare versioned2.version) match { +- case VectorClock.Before ⇒ versioned2 // version 1 is BEFORE (older), use version 2 +- case VectorClock.After ⇒ versioned1 // version 1 is AFTER (newer), use version 1 +- case VectorClock.Concurrent ⇒ versioned1 // can't establish a causal relationship between versions => conflict - keeping version 1 ++ ++ /** ++ * The result of comparing two Versioned objects. ++ * Either: ++ * {{{ ++ * 1) v1 is BEFORE v2 => Before ++ * 2) v1 is AFTER t2 => After ++ * 3) v1 happens CONCURRENTLY to v2 => Concurrent ++ * }}} ++ */ ++ sealed trait Ordering ++ case object Before extends Ordering ++ case object After extends Ordering ++ case object Concurrent extends Ordering ++ ++ /** ++ * Returns or 'Ordering' for the two 'Versioned' instances. ++ */ ++ def compare[T <: Versioned[T]](versioned1: Versioned[T], versioned2: Versioned[T]): Ordering = { ++ if (versioned1.version <> versioned2.version) Concurrent ++ else if (versioned1.version < versioned2.version) Before ++ else After ++ } ++ ++ /** ++ * Returns the Versioned that have the latest version. ++ */ ++ def latestVersionOf[T <: Versioned[T]](versioned1: T, versioned2: T): T = { ++ compare(versioned1, versioned2) match { ++ case Concurrent ⇒ versioned2 ++ case Before ⇒ versioned2 ++ case After ⇒ versioned1 + } + } + } + + /** +- * Representation of a Vector-based clock (counting clock), inspired by Lamport logical clocks. +- * {{ +- * Reference: +- * 1) Leslie Lamport (1978). ""Time, clocks, and the ordering of events in a distributed system"". Communications of the ACM 21 (7): 558-565. +- * 2) Friedemann Mattern (1988). ""Virtual Time and Global States of Distributed Systems"". Workshop on Parallel and Distributed Algorithms: pp. 215-226 +- * }} ++ * VectorClock module with helper classes and methods. ++ * ++ * Based on code from the 'vlock' VectorClock library by Coda Hale. + */ +-case class VectorClock( +- versions: Vector[VectorClock.Entry] = Vector.empty[VectorClock.Entry], +- timestamp: Long = System.currentTimeMillis) { +- import VectorClock._ ++object VectorClock { + +- def compare(other: VectorClock): Ordering = VectorClock.compare(this, other) ++ /** ++ * Hash representation of a versioned node name. ++ */ ++ class Node private (val name: String) extends Serializable {","Because I needed a specific apply method to create the Node instance. Same signature as the generated one but different impl: + def apply(name: String): Node = new Node(hash(name)) +",cf3fa9fa3ce9e9312db0922370c93ce1af9db7c8 +419666,0,"Who do you handle capacity violations? (In case of bounded Deque)""",2012-02-06 06:23:31,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/307#discussion_r419666,2012-02-06T17:23:31Z,2012-02-28T09:22:30Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/Stash.scala,,,,,1,"@@ -0,0 +1,97 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++package akka.actor ++ ++import akka.dispatch.{ Envelope, DequeBasedMessageQueue } ++ ++/** ++ * The `Stash` trait enables an actor to temporarily stash away messages that can not or ++ * should not be handled using the actor's current behavior. ++ *

++ * Example: ++ *

++ *    class ActorWithProtocol extends Actor with Stash {
++ *      def receive = {
++ *        case ""open"" ⇒
++ *          unstashAll {
++ *            case ""write"" ⇒ // do writing...
++ *            case ""close"" ⇒
++ *              unstashAll()
++ *              context.unbecome()
++ *            case msg ⇒ stash()
++ *          }
++ *        case ""done"" ⇒ // done
++ *        case msg    ⇒ stash()
++ *      }
++ *    }
++ *  
++ * ++ * Note that the `Stash` trait can only be used together with actors that have a deque-based ++ * mailbox. Actors can be configured to use a deque-based mailbox using a configuration like ++ * the following: ++ *
++ *  akka {
++ *    actor {
++ *      default-dispatcher {
++ *        mailboxType = ""akka.dispatch.UnboundedDequeBasedMailbox""
++ *      }
++ *    }
++ *  }
++ *  
++ */ ++trait Stash { ++ thisActor: Actor ⇒ ++ ++ /* The private stash of the actor. It is only accessible using `stash()` and ++ * `unstashAll()`. ++ */ ++ private[this] var theStash = Vector.empty[Envelope] ++ ++ /* The actor's deque-based message queue. ++ * `mailbox.queue` is the underlying `Deque`. ++ */ ++ private[this] val mailbox: DequeBasedMessageQueue = { ++ context.asInstanceOf[ActorCell].mailbox match { ++ case queue: DequeBasedMessageQueue ⇒ queue ++ case other ⇒ throw new ActorInitializationException(self, ""UnboundedDequeBasedMailbox required, got: "" + other.getClass()) ++ } ++ } ++ ++ /** ++ * Adds the current message (the message that the actor received last) to the ++ * actor's stash. ++ */ ++ def stash(): Unit = theStash :+= context.asInstanceOf[ActorCell].currentMessage ++ ++ /** ++ * Prepends all messages in the stash to the mailbox, and then clears the stash. ++ */ ++ def unstashAll(): Unit = { ++ theStash.reverseIterator foreach mailbox.queue.addFirst","Who do you handle capacity violations? (In case of bounded Deque) +",8ea949857b39388ac25bdc08df7feee3757f3ee9 +362698,2,"Still don't like this one""",2012-01-18 02:06:53,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/217#discussion_r362698,2012-01-18T13:06:53Z,2012-01-18T16:57:19Z,viktorklang,CONTRIBUTOR,akka-camel/src/main/scala/akka/camel/internal/component/ActorComponent.scala,,,,,1,"@@ -0,0 +1,303 @@ ++package akka.camel.internal.component ++ ++/** ++ * Copyright (C) 2009-2010 Scalable Solutions AB ++ */ ++ ++import java.util.{Map => JMap} ++ ++import org.apache.camel._ ++import org.apache.camel.impl.{DefaultProducer, DefaultEndpoint, DefaultComponent} ++ ++import akka.actor._ ++ ++import scala.reflect.BeanProperty ++import akka.dispatch.Await ++import akka.util.{Duration, Timeout} ++import akka.util.duration._ ++import akka.camel.{Camel, CamelExchangeAdapter, Ack, Failure, Message, BlockingOrNot, Blocking, NonBlocking} ++import java.util.concurrent.TimeoutException ++ ++private[camel] case class Path(actorPath: String) { ++ require(actorPath != null) ++ require(actorPath.length() > 0) ++ def toCamelPath = ""actor://path:%s"" format actorPath ++} ++ ++private[camel] object Path{ ++ def apply(actorRef: ActorRef) = new Path(actorRef.path.toString) ++ def fromCamelPath(camelPath : String) = camelPath match { ++ case id if id startsWith ""path:"" => new Path(id substring 5) ++ case _ => throw new IllegalArgumentException(""Invalid path: [%s] - should be path:"" format camelPath) ++ } ++} ++ ++ ++ ++/** ++ * Camel component for sending messages to and receiving replies from (untyped) actors. ++ * ++ * @see akka.camel.component.ActorEndpoint ++ * @see akka.camel.component.ActorProducer ++ * ++ * @author Martin Krasser ++ */ ++class ActorComponent(camel : Camel) extends DefaultComponent { ++ def createEndpoint(uri: String, remaining: String, parameters: JMap[String, Object]): ActorEndpoint = { ++ val path = Path.fromCamelPath(remaining) ++ new ActorEndpoint(uri, this, path, camel) ++ } ++} ++ ++ ++/** ++ * TODO fix the doc to be consistent with implementation ++ * Camel endpoint for sending messages to and receiving replies from (untyped) actors. Actors ++ * are referenced using actor endpoint URIs of the following format: ++ * actor:, ++ * actor:id:[] and ++ * actor:uuid:[], ++ * where refers to ActorRef.id and ++ * refers to the String-representation od ActorRef.uuid. In URIs that contain ++ * id: or uuid:, an actor identifier (id or uuid) is optional. In this ++ * case, the in-message of an exchange produced to this endpoint must contain a message header ++ * with name CamelActorIdentifier and a value that is the target actor's identifier. ++ * If the URI contains an actor identifier, a message with a CamelActorIdentifier ++ * header overrides the identifier in the endpoint URI. ++ * ++ * @see akka.camel.component.ActorComponent ++ * @see akka.camel.component.ActorProducer ++ ++ * @author Martin Krasser ++ */ ++class ActorEndpoint(uri: String, ++ comp: ActorComponent, ++ val path: Path, ++ camel : Camel) extends DefaultEndpoint(uri, comp) with ActorEndpointConfig{ ++ ++ ++ ++ /** ++ * @throws UnsupportedOperationException ++ */ ++ def createConsumer(processor: Processor): org.apache.camel.Consumer = ++ throw new UnsupportedOperationException(""actor consumer not supported yet"") ++ ++ /** ++ * Creates a new ActorProducer instance initialized with this endpoint. ++ */ ++ def createProducer: ActorProducer = new ActorProducer(this, camel) ++ ++ /** ++ * Returns true. ++ */ ++ def isSingleton: Boolean = true ++} ++ ++trait ActorEndpointConfig{ ++ def getEndpointUri : String ++ def path : Path ++ /** ++ * When endpoint is outCapable (can produce responses) outTimeout is the maximum time ++ * the endpoint can take to send the response back. It defaults to Int.MaxValue seconds. ++ * It can be overwritten by setting @see blocking property ++ */ ++ @BeanProperty var outTimeout: Duration = Int.MaxValue seconds ++ ++ ++ /** ++ * Whether to block caller thread during two-way message exchanges with (untyped) actors. This is ++ * set via the blocking=true|false endpoint URI parameter. Default value is ++ * false. ++ */ ++ @BeanProperty var blocking: BlockingOrNot = NonBlocking","Still don't like this one +",457354db8ba6b42dbacc246c11f0ff15e38ebab4 +362858,1,"to be cool:)""",2012-01-18 03:06:15,piotrga,akka,akka,,https://github.com/akka/akka-core/pull/217#discussion_r362858,2012-01-18T14:06:15Z,2012-01-18T16:57:21Z,piotrga,CONTRIBUTOR,akka-camel/src/main/scala/akka/camelexamples/_2_SupervisedConsumers.scala,,26.0,,,26,"@@ -0,0 +1,37 @@ ++package akka.camelexamples ++ ++import akka.actor.{PoisonPill, Terminated, Props, ActorSystem, Actor} ++import ExamplesSupport._ ++import RichString._ ++ ++ ++object SupervisedConsumersExample extends App{ ++ ++ val system = ActorSystem(""test1"") ++ ++ system.actorOf(Props(new Actor{ ++ context.watch(context.actorOf(Props(faultHandler = retry3xWithin1s, creator = () => new EndpointManager))) ++ protected def receive = { ++ case Terminated(ref) => system.shutdown() ++ } ++ })) ++ ++ ++ ""data/input/CamelConsumer/file1.txt"" << ""test data ""+math.random ++} ++ ++class EndpointManager extends Actor { ++ ++ override def preStart() { ++ self ! Props[SysOutConsumer]","to be cool:) +",457354db8ba6b42dbacc246c11f0ff15e38ebab4 +363036,0,"Like something you put in your configuration file""",2012-01-18 03:57:59,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/217#discussion_r363036,2012-01-18T14:57:59Z,2012-01-18T16:57:21Z,viktorklang,CONTRIBUTOR,akka-camel/src/main/scala/akka/camel/Consumer.scala,,33.0,,,1,"@@ -1,144 +1,71 @@ + /** +- * Copyright (C) 2009-2010 Typesafe Inc. ++ * Copyright (C) 2009-2010 Scalable Solutions AB + */ + + package akka.camel + +-import org.apache.camel.model.{ RouteDefinition, ProcessorDefinition } ++import org.apache.camel.model.{RouteDefinition, ProcessorDefinition} + + import akka.actor._ ++import akka.util.Duration ++import akka.util.duration._ + + /** + * Mixed in by Actor implementations that consume message from Camel endpoints. + * + * @author Martin Krasser + */ +-trait Consumer { this: Actor ⇒ +- import RouteDefinitionHandler._ ++trait Consumer extends Actor with ConsumerConfig{ + +- /** +- * The default route definition handler is the identity function +- */ +- private[camel] var routeDefinitionHandler: RouteDefinitionHandler = identity ++ def endpointUri : String + +- /** +- * Returns the Camel endpoint URI to consume messages from. +- */ +- def endpointUri: String +- +- /** +- * Determines whether two-way communications between an endpoint and this consumer actor +- * should be done in blocking or non-blocking mode (default is non-blocking). This method +- * doesn't have any effect on one-way communications (they'll never block). +- */ +- def blocking = false ++ CamelExtension(context.system).registerConsumer(endpointUri, this, activationTimeout) ++} + +- /** +- * Determines whether one-way communications between an endpoint and this consumer actor +- * should be auto-acknowledged or system-acknowledged. +- */ +- def autoack = true + +- /** +- * Sets the route definition handler for creating a custom route to this consumer instance. +- */ +- def onRouteDefinition(h: RouteDefinition ⇒ ProcessorDefinition[_]): Unit = onRouteDefinition(from(h)) ++trait ConsumerConfig{ ++ //TODO: Explain the parameters better with some examples! + + /** +- * Sets the route definition handler for creating a custom route to this consumer instance. +- *

+- * Java API. ++ * How long should the actor wait for activation before it fails. + */ +- def onRouteDefinition(h: RouteDefinitionHandler): Unit = routeDefinitionHandler = h +-} +- +-/** +- * Java-friendly Consumer. +- * +- * Subclass this abstract class to create an MDB-style untyped consumer actor. This +- * class is meant to be used from Java. +- * +- * @author Martin Krasser +- */ +-abstract class UntypedConsumerActor extends UntypedActor with Consumer { +- final override def endpointUri = getEndpointUri +- final override def blocking = isBlocking +- final override def autoack = isAutoack ++ def activationTimeout: Duration = 10 seconds","Like something you put in your configuration file +",457354db8ba6b42dbacc246c11f0ff15e38ebab4 +363247,0,"If there are no references to it, it means that it's been terminated, if it has been terminated then DeathWAtch has been triggered. No need for WeakHashMap""",2012-01-18 04:39:46,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/217#discussion_r363247,2012-01-18T15:39:46Z,2012-01-18T16:57:22Z,viktorklang,CONTRIBUTOR,akka-camel/src/main/scala/akka/camel/internal/ActivationTracker.scala,,80.0,,,80,"@@ -0,0 +1,80 @@ ++package akka.camel.internal ++ ++import akka.actor._ ++import akka.camel._ ++import collection.mutable.WeakHashMap ++import akka.event.Logging.Warning ++ ++ ++ ++class ActivationTracker extends Actor{ ++ ++ val activations = new WeakHashMap[ActorRef, ActivationStateMachine] ++ ++ class ActivationStateMachine { ++ private[this] var awaitingActivation : List[ActorRef] = Nil ++ private[this] var awaitingDeActivation : List[ActorRef] = Nil ++ private[this] var activationFailure : Option[Throwable] = None ++ ++ var receive : Receive = notActivated ++ ++ def notActivated : Receive = { ++ case AwaitActivation(ref) => awaitingActivation ::= sender ++ case AwaitDeActivation(ref) => awaitingDeActivation ::= sender ++ ++ case msg @ EndpointActivated(ref) => { ++ migration.Migration.EventHandler.debug(ref+"" activated"") ++ awaitingActivation.foreach(_ ! msg) ++ awaitingActivation = Nil ++ receive = activated ++ } ++ ++ case EndpointFailedToActivate(ref, cause) => { ++ migration.Migration.EventHandler.debug(ref+"" failed to activate"") ++ activationFailure = Option(cause) ++ awaitingActivation.foreach(_ ! EndpointFailedToActivate(ref, cause)) ++ awaitingActivation = Nil ++ receive = failedToActivate ++ } ++ } ++ ++ def activated : Receive = { ++ case AwaitActivation(ref) => sender ! EndpointActivated(ref) ++ case AwaitDeActivation(ref) => awaitingDeActivation ::= sender ++ case EndpointDeActivated(ref) => { ++ awaitingDeActivation foreach (_ ! EndpointDeActivated(ref)) ++ awaitingDeActivation = Nil ++ context.stop(self) ++ } ++ case msg : EndpointFailedToDeActivate => { ++ awaitingDeActivation foreach (_ ! msg) ++ awaitingDeActivation = Nil ++ } ++ } ++ ++ def failedToActivate : Receive = { ++ case AwaitActivation(ref) => sender ! EndpointFailedToActivate(ref, activationFailure.get) ++ case AwaitDeActivation(ref) => sender ! EndpointFailedToActivate(ref, activationFailure.get) ++ } ++ ++ } ++ ++ override def preStart() { ++ context.system.eventStream.subscribe(self, classOf[ActivationMessage]) ++ } ++ ++ override def receive = { ++ case msg @ ActivationMessage(ref) =>{ ++ try{ ++ activations.getOrElseUpdate(ref, new ActivationStateMachine).receive(msg)","If there are no references to it, it means that it's been terminated, if it has been terminated then DeathWAtch has been triggered. No need for WeakHashMap +",457354db8ba6b42dbacc246c11f0ff15e38ebab4 +314470,0,"Perhaps a ref to the remoting docs could be of interest here.""",2011-12-25 04:25:52,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/187#discussion_r314470,2011-12-25T15:25:52Z,2011-12-25T15:25:52Z,viktorklang,CONTRIBUTOR,akka-docs/java/untyped-actors.rst,,222.0,,,27,"@@ -205,9 +210,16 @@ result:: + getContext().actorFor(""/user/serviceA/aggregator"") // will look up this absolute path + getContext().actorFor(""../joe"") // will look up sibling beneath same supervisor + ++The supplied path is parsed as a :class:`java.net.URI`, which basically means ++that it is split on ``/`` into path elements. If the path starts with ``/``, it ++is absolute and the look-up starts at the root guardian (which is the parent of ++``""/user""``); otherwise it starts at the current actor. If a path element equals ++``..``, the look-up will take a step “up” towards the supervisor of the ++currently traversed actor, otherwise it will step “down” to the named child. + It should be noted that the ``..`` in actor paths here always means the logical +-structure, i.e. the supervisor. Remote actor addresses may also be looked up, +-if remoting is enabled:: ++structure, i.e. the supervisor. ++ ++Remote actor addresses may also be looked up, if remoting is enabled::","Perhaps a ref to the remoting docs could be of interest here. +",1be9c1d99db3db0384b5ba10790b2de70db30147 +308613,0,"Is this threadsafe?""",2011-12-21 02:19:34,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/182#discussion_r308613,2011-12-21T13:19:34Z,2011-12-21T22:47:21Z,viktorklang,CONTRIBUTOR,akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala,,,,,1,"@@ -422,23 +423,48 @@ abstract class ActorModelSpec extends AkkaSpec with DefaultTimeout { + } + } + ++object DispatcherModelSpec { ++ val config = """""" ++ dispatcher { ++ type = Dispatcher ++ } ++ boss { ++ type = PinnedDispatcher ++ } ++ """""" ++} ++ + @org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) +-class DispatcherModelSpec extends ActorModelSpec { ++class DispatcherModelSpec extends ActorModelSpec(DispatcherModelSpec.config) { + import ActorModelSpec._ + +- def newInterceptedDispatcher = ThreadPoolConfigDispatcherBuilder(config ⇒ +- new Dispatcher(system.dispatcherFactory.prerequisites, ""foo"", system.settings.DispatcherThroughput, +- system.settings.DispatcherThroughputDeadlineTime, system.dispatcherFactory.MailboxType, +- config, system.settings.DispatcherDefaultShutdown) with MessageDispatcherInterceptor, +- ThreadPoolConfig()).build.asInstanceOf[MessageDispatcherInterceptor] ++ var dispatcherCount = 0 ++ ++ override def registerInterceptedDispatcher(): MessageDispatcherInterceptor = { ++ // use new key for each invocation, since the MessageDispatcherInterceptor holds state ++ dispatcherCount += 1","Is this threadsafe? +",ed2fb14dcf0120a6c126fe9c99038d897dbcdf0d +295443,0,"Fixed""",2011-12-14 13:37:48,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/160#discussion_r295443,2011-12-15T00:37:48Z,2011-12-15T16:19:19Z,viktorklang,CONTRIBUTOR,akka-docs/scala/typed-actors.rst,,,,,1,"@@ -4,186 +4,160 @@ Typed Actors (Scala) + .. sidebar:: Contents + + .. contents:: :local: +- +-The Typed Actors are implemented through `Typed Actors `_. It uses AOP through `AspectWerkz `_ to turn regular POJOs into asynchronous non-blocking Actors with semantics of the Actor Model. Each method dispatch is turned into a message that is put on a queue to be processed by the Typed Actor sequentially one by one. + +-If you are using the `Spring Framework `_ then take a look at Akka's `Spring integration `_. ++Akka Typed Actors is an implementation of the `Active Objects `_ pattern. ++Essentially turning method invocations into asynchronous dispatch instead of synchronous that has been the default way since Smalltalk came out. + +-**WARNING:** Do not configure to use a ``BalancingDispatcher`` with your ``TypedActors``, it just isn't safe with how ``TypedActors`` currently are implemented. This limitation will most likely be removed in the future. ++Typed Actors consist of 2 ""parts"", a public interface and an implementation, and if you've done any work in ""enterprise"" Java, this will be very familiar to you. As with normal Actors you have an external API (the public interface instance) that will delegate methodcalls asynchronously to ++a private instance of the implementation. + +-Creating Typed Actors +---------------------- +- +-**IMPORTANT:** The Typed Actors class must have access modifier 'public' (which is default) and can't be an inner class (unless it is an inner class in an 'object'). ++The advantage of Typed Actors vs. Actors is that with TypedActors you have a static contract, and don't need to define your own messages, the downside is that it places some limitations on what you can do and what you can't, i.e. you can't use become/unbecome. + +-Akka turns POJOs with interface and implementation into asynchronous (Typed) Actors. Akka is using `AspectWerkz’s Proxy `_ implementation, which is the `most performant `_ proxy implementation there exists. ++Typed Actors are implemented using `JDK Proxies `_ which provide a pretty easy-worked API to intercept method calls. + +-In order to create a Typed Actor you have to subclass the ``TypedActor`` base class. + +-Here is an example. ++The tools of the trade ++---------------------- + +-If you have a POJO with an interface implementation separation like this: ++Before we create our first Typed Actor we should first go through the tools that we have at our disposal, ++it's located in ``akka.actor.TypedActor``. + +-.. code-block:: scala ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: typed-actor-extension-tools + +- import akka.actor.TypedActor ++.. warning:: ++ ++ Same as not exposing ``this`` of an Akka Actor, it's important not to expose ``this`` of a Typed Actor, ++ instead you should pass the external proxy reference, which is obtained from within your Typed Actor as ++ ``TypedActor.self``, this is your external identity, as the ``ActorRef`` is the external identity of ++ and Akka Actor.","Fixed +",9d2ab2e7145ed1e200ed29aee42f9a5734f108ab +297170,0,"Not only that, but I don't believe that Lift uses akka futures anyway. """"or"""" is definitely better than """"orElse"""" though I still like """"race."""" """,2011-12-15 06:41:39,nuttycom,akka,akka,,https://github.com/akka/akka-core/pull/147#discussion_r297170,2011-12-15T17:41:39Z,2011-12-15T17:41:39Z,nuttycom,NONE,akka-actor/src/main/scala/akka/dispatch/Future.scala,,398.0,,,615,"@@ -524,67 +339,63 @@ sealed trait Future[+T] extends japi.Future[T] { + def value: Option[Either[Throwable, T]] + + /** +- * Returns the successful result of this Future if it exists. +- */ +- final def result: Option[T] = value match { +- case Some(Right(r)) ⇒ Some(r) +- case _ ⇒ None +- } +- +- /** +- * Returns the contained exception of this Future if it exists. +- */ +- final def exception: Option[Throwable] = value match { +- case Some(Left(e)) ⇒ Some(e) +- case _ ⇒ None +- } +- +- /** + * When this Future is completed, apply the provided function to the + * Future. If the Future has already been completed, this will apply +- * immediately. Will not be called in case of a timeout, which also holds if +- * corresponding Promise is attempted to complete after expiry. Multiple ++ * immediately. Multiple + * callbacks may be registered; there is no guarantee that they will be + * executed in a particular order. + */ +- def onComplete(func: Future[T] ⇒ Unit): this.type ++ def onComplete(func: Either[Throwable, T] ⇒ Unit): this.type + + /** + * When the future is completed with a valid result, apply the provided + * PartialFunction to the result. See `onComplete` for more details. + *

+-   *   future onResult {
++   *   future onSuccess {
+    *     case Foo ⇒ target ! ""foo""
+    *     case Bar ⇒ target ! ""bar""
+    *   }
+    * 
+ */ +- final def onResult(pf: PartialFunction[T, Unit]): this.type = onComplete { +- _.value match { +- case Some(Right(r)) if pf isDefinedAt r ⇒ pf(r) +- case _ ⇒ +- } ++ final def onSuccess[U](pf: PartialFunction[T, U]): this.type = onComplete { ++ case Right(r) if pf isDefinedAt r ⇒ pf(r) ++ case _ ⇒ + } + + /** + * When the future is completed with an exception, apply the provided + * PartialFunction to the exception. See `onComplete` for more details. + *
+-   *   future onException {
++   *   future onFailure {
+    *     case NumberFormatException ⇒ target ! ""wrong format""
+    *   }
+    * 
+ */ +- final def onException(pf: PartialFunction[Throwable, Unit]): this.type = onComplete { +- _.value match { +- case Some(Left(ex)) if pf isDefinedAt ex ⇒ pf(ex) +- case _ ⇒ +- } ++ final def onFailure[U](pf: PartialFunction[Throwable, U]): this.type = onComplete { ++ case Left(ex) if pf isDefinedAt ex ⇒ pf(ex) ++ case _ ⇒ + } + +- def onTimeout(func: Future[T] ⇒ Unit): this.type ++ /** ++ * Returns a failure projection of this Future ++ * If `this` becomes completed with a failure, that failure will be the success of the returned Future ++ * If `this` becomes completed with a result, then the returned future will fail with a NoSuchElementException ++ */ ++ final def failed: Future[Throwable] = { ++ val p = Promise[Throwable]() ++ this.onComplete { ++ case Left(t) ⇒ p success t ++ case Right(r) ⇒ p failure new NoSuchElementException(""Future.failed not completed with a throwable. Instead completed with: "" + r) ++ } ++ p ++ } + +- def orElse[A >: T](fallback: ⇒ A): Future[A] ++ /** ++ * Creates a Future that will be the result of the first completed Future of this and the Future that was passed into this. ++ * This is semantically the same as: Future.firstCompletedOf(Seq(this, that)) ++ */ ++ //FIXME implement as The result of any of the Futures, or if oth failed, the first failure ++ def orElse[A >: T](that: Future[A]): Future[A] = Future.firstCompletedOf(List(this, that)) //TODO Optimize","Not only that, but I don't believe that Lift uses akka futures anyway. ""or"" is definitely better than ""orElse"" though I still like ""race."" +",0af92f24400f1b05d1919be54dfd822037f0076f +284870,0,"Null-object pattern"""" sounds more academic""",2011-12-10 06:40:39,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/144#discussion_r284870,2011-12-10T17:40:39Z,2011-12-13T15:06:06Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/routing/Routing.scala,,,,,1,"@@ -73,62 +76,105 @@ object RouterType { + */ + case class RoutedProps private[akka] ( + routerFactory: () ⇒ Router, +- connectionManager: ConnectionManager, +- timeout: Timeout = RoutedProps.defaultTimeout, +- localOnly: Boolean = RoutedProps.defaultLocalOnly) { ++ connectionManager: ConnectionManager) { + + // Java API +- def this(creator: Creator[Router], connectionManager: ConnectionManager, timeout: Timeout, localOnly: Boolean) { +- this(() ⇒ creator.create(), connectionManager, timeout, localOnly) ++ def this(creator: Creator[Router], connectionManager: ConnectionManager) { ++ this(() ⇒ creator.create(), connectionManager) + } ++} ++ ++///** ++// * The Router is responsible for sending a message to one (or more) of its connections. Connections are stored in the ++// * {@link FailureDetector} and each Router should be linked to only one {@link FailureDetector}. ++// * ++// * @author Jonas Bonér ++// */ ++//trait Router { ++// ++// /** ++// * Initializes this Router with a given set of Connections. The Router can use this datastructure to ask for ++// * the current connections, signal that there were problems with one of the connections and see if there have ++// * been changes in the connections. ++// * ++// * This method is not threadsafe, and should only be called once ++// * ++// * JMM Guarantees: ++// * This method guarantees that all changes made in this method, are visible before one of the routing methods is called. ++// */ ++// def init(connectionManager: ConnectionManager) ++// ++// /** ++// * Routes the message to one of the connections. ++// * ++// * @throws RoutingException if something goes wrong while routing the message ++// */ ++// def route(message: Any)(implicit sender: ActorRef) ++// ++// /** ++// * Routes the message using a timeout to one of the connections and returns a Future to synchronize on the ++// * completion of the processing of the message. ++// * ++// * @throws RoutingExceptionif something goes wrong while routing the message. ++// */ ++// def route[T](message: Any, timeout: Timeout): Future[T] ++//} ++// ++///** ++// * An {@link AkkaException} thrown when something goes wrong while routing a message ++// */ ++//class RoutingException(message: String) extends AkkaException(message) ++// + ++/** ++ * A RoutedActorRef is an ActorRef that has a set of connected ActorRef and it uses a Router to send a message to ++ * on (or more) of these actors. ++ */ ++private[akka] class RoutedActorRef(_system: ActorSystemImpl, _props: Props, _supervisor: InternalActorRef, _path: ActorPath) ++ extends LocalActorRef( ++ _system, ++ _props.copy(creator = _props.routerConfig), ++ _supervisor, ++ _path) { ++ ++ val route: Routing.Route = _props.routerConfig.createRoute(_props.creator, actorContext) ++ ++ override def !(message: Any)(implicit sender: ActorRef = null) { ++ route(message) match { ++ case null ⇒ super.!(message)(sender) ++ case ref: ActorRef ⇒ ref.!(message)(sender) ++ case refs: Traversable[ActorRef] ⇒ refs foreach (_.!(message)(sender)) ++ } ++ } + } + +-object RoutedProps { +- final val defaultTimeout = Timeout(Duration.MinusInf) +- final val defaultLocalOnly = false ++trait RouterConfig extends Function0[Actor] { ++ def adaptFromDeploy(deploy: Option[Deploy]): RouterConfig ++ def createRoute(creator: () ⇒ Actor, actorContext: ActorContext): Routing.Route + } + + /** +- * The Router is responsible for sending a message to one (or more) of its connections. Connections are stored in the +- * {@link FailureDetector} and each Router should be linked to only one {@link FailureDetector}. +- * +- * @author Jonas Bonér ++ * Routing configuration that indicates no routing. ++ * Oxymoron style.","""Null-object pattern"" sounds more academic +",134fac4bfe8d6f8b4e9b96dfbfdf532d48ae3c86 +269700,2,"DO NOT USE THIS EXCEPT INTERNALLY IN AKKA""",2011-12-05 02:03:00,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/119#discussion_r269700,2011-12-05T13:03:00Z,2011-12-05T21:48:29Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorRef.scala,,163.0,,,102,"@@ -118,14 +111,76 @@ abstract class ActorRef extends java.lang.Comparable[ActorRef] with Serializable + */ + def isTerminated: Boolean + +- override def hashCode: Int = HashCode.hash(HashCode.SEED, address) ++ // FIXME RK check if we should scramble the bits or whether they can stay the same ++ override def hashCode: Int = path.hashCode + +- override def equals(that: Any): Boolean = { +- that.isInstanceOf[ActorRef] && +- that.asInstanceOf[ActorRef].address == address ++ override def equals(that: Any): Boolean = that match { ++ case other: ActorRef ⇒ path == other.path ++ case _ ⇒ false + } + +- override def toString = ""Actor[%s]"".format(address) ++ override def toString = ""Actor[%s]"".format(path) ++} ++ ++/** ++ * This trait represents the Scala Actor API ++ * There are implicit conversions in ../actor/Implicits.scala ++ * from ActorRef -> ScalaActorRef and back ++ */ ++trait ScalaActorRef { ref: ActorRef ⇒ ++ ++ /** ++ * Sends a one-way asynchronous message. E.g. fire-and-forget semantics. ++ *

++ * ++ * If invoked from within an actor then the actor reference is implicitly passed on as the implicit 'sender' argument. ++ *

++ * ++ * This actor 'sender' reference is then available in the receiving actor in the 'sender' member variable, ++ * if invoked from within an Actor. If not then no sender is available. ++ *

++   *   actor ! message
++   * 
++ *

++ */ ++ def !(message: Any)(implicit sender: ActorRef = null): Unit ++ ++ /** ++ * Sends a message asynchronously, returning a future which may eventually hold the reply. ++ */ ++ def ?(message: Any)(implicit timeout: Timeout): Future[Any] ++ ++ /** ++ * Sends a message asynchronously, returning a future which may eventually hold the reply. ++ * The implicit parameter with the default value is just there to disambiguate it from the version that takes the ++ * implicit timeout ++ */ ++ def ?(message: Any, timeout: Timeout)(implicit ignore: Int = 0): Future[Any] = ?(message)(timeout) ++} ++ ++/** ++ * Internal trait for assembling all the functionality needed internally on ++ * ActorRefs. NOTE THAT THIS IS NOT A STABLE EXTERNAL INTERFACE!","DO NOT USE THIS EXCEPT INTERNALLY IN AKKA +",9d7597c7282711889d74bd9b4d7bdae5ea254104 +479831,0,"Can such a scenario exist such that both connection and reconnectionFuture is Some(...) ? If not, you might want to encode it as Option[Either[Connection, Cancellable]]""",2012-02-22 23:26:23,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/350#discussion_r479831,2012-02-23T10:26:23Z,2012-03-06T19:30:30Z,viktorklang,CONTRIBUTOR,akka-amqp/src/main/scala/akka/amqp/FaultTolerantConnectionActor.scala,,,,,1,"@@ -0,0 +1,160 @@ ++/** ++ * Copyright (C) 2009-2010 Scalable Solutions AB ++ */ ++ ++package akka.amqp ++ ++import java.io.IOException ++import com.rabbitmq.client._ ++import akka.event.Logging ++import akka.actor._ ++import akka.util.duration._ ++import akka.amqp.AMQP.{ ConsumerParameters, ProducerParameters, ConnectionParameters } ++import java.util.UUID ++ ++private[amqp] class FaultTolerantConnectionActor(connectionParameters: ConnectionParameters) extends Actor { ++ import connectionParameters._ ++ ++ val log = Logging(context.system, this) ++ ++ val connectionFactory: ConnectionFactory = new ConnectionFactory() ++ connectionFactory.setUsername(username) ++ connectionFactory.setPassword(password) ++ connectionFactory.setVirtualHost(virtualHost) ++ ++ var connection: Option[Connection] = None ++ var reconnectionFuture: Option[Cancellable] = None","Can such a scenario exist such that both connection and reconnectionFuture is Some(...) ? If not, you might want to encode it as Option[Either[Connection, Cancellable]] +",e039c380c868b28285dab6fc313025d981ef022b +490636,0,"This should most definitely go into test/resources and not main/resources""",2012-02-27 00:03:53,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/350#discussion_r490636,2012-02-27T11:03:53Z,2012-03-06T19:30:33Z,viktorklang,CONTRIBUTOR,akka-amqp/src/main/resources/application.conf,,,,,1,"@@ -0,0 +1,15 @@ ++example { ++ akka { ++ loglevel = INFO ++ actor { ++ debug { ++ receive = off ++ autoreceive = off ++ lifecycle = off ++ } ++ } ++ amqp { ++ timeout = 2000 ++ } ++ } ++}","This should most definitely go into test/resources and not main/resources +",e039c380c868b28285dab6fc313025d981ef022b +503277,1,"This is so badass I don't even know where to begin""",2012-02-29 09:01:24,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/329#discussion_r503277,2012-02-29T20:01:24Z,2012-03-12T18:22:14Z,viktorklang,CONTRIBUTOR,akka-cluster/src/main/scala/akka/cluster/Node.scala,,,,,1,"@@ -0,0 +1,803 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++ ++package akka.cluster ++ ++import akka.actor._ ++import akka.actor.Status._ ++import akka.remote._ ++import akka.routing._ ++import akka.event.Logging ++import akka.dispatch.Await ++import akka.pattern.ask ++import akka.util._ ++import akka.config.ConfigurationException ++ ++import java.util.concurrent.atomic.{ AtomicReference, AtomicBoolean } ++import java.util.concurrent.TimeUnit._ ++import java.util.concurrent.TimeoutException ++import java.security.SecureRandom ++ ++import scala.collection.immutable.{ Map, SortedSet } ++import scala.annotation.tailrec ++ ++import com.google.protobuf.ByteString ++ ++/** ++ * Interface for membership change listener. ++ */ ++trait MembershipChangeListener { ++ def notify(members: SortedSet[Member]): Unit ++} ++ ++/** ++ * Interface for meta data change listener. ++ */ ++trait MetaDataChangeListener { // FIXME add management and notification for MetaDataChangeListener ++ def notify(meta: Map[String, Array[Byte]]): Unit ++} ++ ++// FIXME create Protobuf messages out of all the Gossip stuff - but wait until the prototol is fully stablized. ++ ++/** ++ * Base trait for all cluster messages. All ClusterMessage's are serializable. ++ */ ++sealed trait ClusterMessage extends Serializable ++ ++/** ++ * Cluster commands sent by the USER. ++ */ ++object ClusterAction { ++ ++ /** ++ * Command to join the cluster. Sent when a node (reprsesented by 'address') ++ * wants to join another node (the receiver). ++ */ ++ case class Join(address: Address) extends ClusterMessage ++ ++ /** ++ * Command to set a node to Up (from Joining). ++ */ ++ case object Up extends ClusterMessage ++ ++ /** ++ * Command to leave the cluster. ++ */ ++ case object Leave extends ClusterMessage ++ ++ /** ++ * Command to mark node as temporary down. ++ */ ++ case object Down extends ClusterMessage ++ ++ /** ++ * Command to mark a node to be removed from the cluster immediately. ++ */ ++ case object Exit extends ClusterMessage ++ ++ /** ++ * Command to remove a node from the cluster immediately. ++ */ ++ case object Remove extends ClusterMessage ++} ++ ++/** ++ * Represents the address and the current status of a cluster member node. ++ */ ++case class Member(address: Address, status: MemberStatus) extends ClusterMessage ++ ++/** ++ * Envelope adding a sender address to the gossip. ++ */ ++case class GossipEnvelope(sender: Member, gossip: Gossip) extends ClusterMessage ++ ++/** ++ * Defines the current status of a cluster member node ++ * ++ * Can be one of: Joining, Up, Leaving, Exiting and Down. ++ */ ++sealed trait MemberStatus extends ClusterMessage ++object MemberStatus { ++ case object Joining extends MemberStatus ++ case object Up extends MemberStatus ++ case object Leaving extends MemberStatus ++ case object Exiting extends MemberStatus ++ case object Down extends MemberStatus ++ case object Removed extends MemberStatus ++} ++ ++// sealed trait PartitioningStatus ++// object PartitioningStatus { ++// case object Complete extends PartitioningStatus ++// case object Awaiting extends PartitioningStatus ++// } ++ ++// case class PartitioningChange( ++// from: Address, ++// to: Address, ++// path: PartitionPath, ++// status: PartitioningStatus) ++ ++/** ++ * Represents the overview of the cluster, holds the cluster convergence table and set with unreachable nodes. ++ */ ++case class GossipOverview( ++ seen: Map[Address, VectorClock] = Map.empty[Address, VectorClock], ++ unreachable: Set[Address] = Set.empty[Address]) { ++ ++ override def toString = ++ ""GossipOverview(seen = ["" + seen.mkString("", "") + ++ ""], unreachable = ["" + unreachable.mkString("", "") + ++ ""])"" ++} ++ ++/** ++ * Represents the state of the cluster; cluster ring membership, ring convergence, meta data - all versioned by a vector clock. ++ */ ++case class Gossip( ++ overview: GossipOverview = GossipOverview(), ++ members: SortedSet[Member], // sorted set of members with their status, sorted by name ++ //partitions: Tree[PartitionPath, Node] = Tree.empty[PartitionPath, Node], // name/partition service ++ //pending: Set[PartitioningChange] = Set.empty[PartitioningChange], ++ meta: Map[String, Array[Byte]] = Map.empty[String, Array[Byte]], ++ version: VectorClock = VectorClock()) // vector clock version ++ extends ClusterMessage // is a serializable cluster message ++ with Versioned[Gossip] { ++ ++ /** ++ * Increments the version for this 'Node'. ++ */ ++ def +(node: VectorClock.Node): Gossip = copy(version = version + node) ++ ++ def +(member: Member): Gossip = { ++ if (members contains member) this ++ else this copy (members = members + member) ++ } ++ ++ /** ++ * Marks the gossip as seen by this node (remoteAddress) by updating the address entry in the 'gossip.overview.seen' ++ * Map with the VectorClock for the new gossip. ++ */ ++ def seen(address: Address): Gossip = ++ this copy (overview = overview copy (seen = overview.seen + (address -> version))) ++ ++ override def toString = ++ ""Gossip("" + ++ ""overview = "" + overview + ++ "", members = ["" + members.mkString("", "") + ++ ""], meta = ["" + meta.mkString("", "") + ++ ""], version = "" + version + ++ "")"" ++} ++ ++/** ++ * FSM actor managing the different cluster nodes states. ++ * Single instance - e.g. serialized access to Node - message after message. ++ */ ++final class ClusterCommandDaemon(system: ActorSystem, node: Node) extends Actor with FSM[MemberStatus, Unit] { ++ ++ // start in JOINING ++ startWith(MemberStatus.Joining, Unit) ++ ++ // ======================== ++ // === IN JOINING === ++ when(MemberStatus.Joining) { ++ case Event(ClusterAction.Up, _) ⇒ ++ node.up() ++ goto(MemberStatus.Up) ++ } ++ ++ // ======================== ++ // === IN UP === ++ when(MemberStatus.Up) { ++ case Event(ClusterAction.Down, _) ⇒ ++ node.downing() ++ goto(MemberStatus.Down) ++ ++ case Event(ClusterAction.Leave, _) ⇒ ++ node.leaving() ++ goto(MemberStatus.Leaving) ++ ++ case Event(ClusterAction.Exit, _) ⇒ ++ node.exiting() ++ goto(MemberStatus.Exiting) ++ ++ case Event(ClusterAction.Remove, _) ⇒ ++ node.removing() ++ goto(MemberStatus.Removed) ++ } ++ ++ // ======================== ++ // === IN LEAVING === ++ when(MemberStatus.Leaving) { ++ case Event(ClusterAction.Down, _) ⇒ ++ node.downing() ++ goto(MemberStatus.Down) ++ ++ case Event(ClusterAction.Remove, _) ⇒ ++ node.removing() ++ goto(MemberStatus.Removed) ++ } ++ ++ // ======================== ++ // === IN EXITING === ++ when(MemberStatus.Exiting) { ++ case Event(ClusterAction.Remove, _) ⇒ ++ node.removing() ++ goto(MemberStatus.Removed) ++ } ++ ++ // ======================== ++ // === IN DOWN === ++ when(MemberStatus.Down) { ++ // FIXME How to transition from DOWN => JOINING when node comes back online. Can't just listen to Gossip message since it is received be another actor. How to fix this? ++ case Event(ClusterAction.Remove, _) ⇒ ++ node.removing() ++ goto(MemberStatus.Removed) ++ } ++ ++ // ======================== ++ // === IN REMOVED === ++ when(MemberStatus.Removed) { ++ case command ⇒ ++ log.warning(""Removed node [{}] received cluster command [{}]"", system.name, command) ++ stay ++ } ++ ++ // ======================== ++ // === GENERIC AND UNHANDLED COMMANDS === ++ whenUnhandled { ++ // should be able to handle Join in any state ++ case Event(ClusterAction.Join(address), _) ⇒ ++ node.joining(address) ++ stay ++ ++ case Event(command, _) ⇒ { ++ log.warning(""Unhandled command [{}] in state [{}]"", command, stateName) ++ stay ++ } ++ } ++} ++ ++/** ++ * Pooled and routed wit N number of configurable instances. ++ * Concurrent access to Node. ++ */ ++final class ClusterGossipDaemon(system: ActorSystem, node: Node) extends Actor { ++ val log = Logging(system, ""ClusterGossipDaemon"")","This is so badass I don't even know where to begin +",cf3fa9fa3ce9e9312db0922370c93ce1af9db7c8 +427299,0,"maybe mention which thing is changed, `m.copy(name = …)`""",2012-02-08 00:10:50,rkuhn,akka,akka,,https://github.com/akka/akka-core/pull/315#discussion_r427299,2012-02-08T11:10:50Z,2012-02-08T13:03:45Z,rkuhn,CONTRIBUTOR,akka-actor/src/main/scala/akka/dispatch/AbstractDispatcher.scala,,,,,1,"@@ -420,8 +420,13 @@ class ThreadPoolExecutorConfigurator(config: Config, prerequisites: DispatcherPr + })(queueFactory ⇒ _.setQueueFactory(queueFactory))) + } + +- def createExecutorServiceFactory(name: String, threadFactory: ThreadFactory): ExecutorServiceFactory = +- threadPoolConfig.createExecutorServiceFactory(name, threadFactory) ++ def createExecutorServiceFactory(id: String, threadFactory: ThreadFactory): ExecutorServiceFactory = { ++ val tf = threadFactory match { ++ case m: MonitorableThreadFactory ⇒ m.copy(m.name + ""-"" + id)","maybe mention which thing is changed, `m.copy(name = …)` +",df1606a8eec75af73917072f27d7bf6a49bd4d7c +415676,0,"all interfaces must be resolved recursively as well, so that doesn't work. My first approach was to try to get collectFirst working but I didn't find a good way, and it is really only some extra HashMap lookups that are performed (initially). I would be""",2012-02-03 09:49:29,patriknw,akka,akka,,https://github.com/akka/akka-core/pull/300#discussion_r415676,2012-02-03T20:49:29Z,2012-02-04T16:38:25Z,patriknw,CONTRIBUTOR,akka-actor/src/main/scala/akka/serialization/Serialization.scala,,,,,1,"@@ -111,10 +114,45 @@ class Serialization(val system: ExtendedActorSystem) extends Extension { + } + + /** +- * Returns the configured Serializer for the given Class, falls back to the Serializer named ""default"" ++ * Returns the configured Serializer for the given Class, falls back to the Serializer named ""default"". ++ * It traverses interfaces and super classes to find any configured Serializer that match ++ * the class name. + */ +- def serializerFor(clazz: Class[_]): Serializer = //TODO fall back on BestMatchClass THEN default AND memoize the lookups +- serializerMap.get(clazz.getName).getOrElse(serializers(""default"")) ++ def serializerFor(clazz: Class[_]): Serializer = { ++ ++ def lookup(c: Class[_]): Option[Serializer] = { ++ val className = c.getName ++ serializerMap.get(className) match { ++ case null ⇒ bindings.get(className) map serializers ++ case serializer ⇒ Some(serializer) ++ } ++ } ++ ++ def resolve(c: Class[_]): Option[Serializer] = { ++ lookup(c) match { ++ case x @ Some(_) ⇒ x ++ case None ⇒ ++ val classes = c.getInterfaces.toList ::: Option(c.getSuperclass).toList ++ classes flatMap resolve headOption","all interfaces must be resolved recursively as well, so that doesn't work. + +My first approach was to try to get collectFirst working but I didn't find a good way, and it is really only some extra HashMap lookups that are performed (initially). + +I would be glad to see a tailrec version, but I don't think it is necessary, since inheritance depth is limited +",bd3766d8a75d43f8a67066e0d3de87b882124aa8 +406347,0,"so, what’s the rationale for not suspending the actor in this case? Or should it in fact be implicitly Resume’d? (I mean in the Directive sense)""",2012-02-01 03:42:11,rkuhn,akka,akka,,https://github.com/akka/akka-core/pull/282#discussion_r406347,2012-02-01T14:42:11Z,2012-02-03T13:05:16Z,rkuhn,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorCell.scala,,486.0,,,1,"@@ -476,31 +475,29 @@ private[akka] class ActorCell( + cancelReceiveTimeout() // FIXME: leave this here??? + messageHandle.message match { + case msg: AutoReceivedMessage ⇒ autoReceiveMessage(messageHandle) ++ // actor can be null when creation fails fatal error ++ case msg if actor == null ⇒ + case msg ⇒ actor(msg) + } + currentMessage = null // reset current message after successful invocation + } catch { +- case e ⇒ ++ case e: InterruptedException ⇒","so, what’s the rationale for not suspending the actor in this case? Or should it in fact be implicitly Resume’d? (I mean in the Directive sense) +",09e13e271b430949b45192f0f28737fbfde56c9d +374470,0,"just verified that the bytecode generated with and without `final` is identical … (vals are always private final fields)""",2012-01-21 21:42:18,rkuhn,akka,akka,,https://github.com/akka/akka-core/pull/242#discussion_r374470,2012-01-22T08:42:18Z,2012-01-22T08:42:18Z,rkuhn,CONTRIBUTOR,akka-remote/src/main/scala/akka/remote/RemoteSettings.scala,,99.0,,,114,"@@ -74,26 +76,26 @@ class RemoteSettings(val config: Config, val systemName: String) { + case other ⇒ other + } + +- val Backlog = getInt(""akka.remote.server.backlog"") ++ final val Backlog = getInt(""akka.remote.server.backlog"") + +- val ExecutionPoolKeepAlive = Duration(getMilliseconds(""akka.remote.server.execution-pool-keepalive""), MILLISECONDS) ++ final val ExecutionPoolKeepAlive = Duration(getMilliseconds(""akka.remote.server.execution-pool-keepalive""), MILLISECONDS) + +- val ExecutionPoolSize = getInt(""akka.remote.server.execution-pool-size"") match { ++ final val ExecutionPoolSize = getInt(""akka.remote.server.execution-pool-size"") match { + case sz if sz < 1 ⇒ throw new IllegalArgumentException(""akka.remote.server.execution-pool-size is less than 1"") + case sz ⇒ sz + } + +- val MaxChannelMemorySize = getBytes(""akka.remote.server.max-channel-memory-size"") match { ++ final val MaxChannelMemorySize = getBytes(""akka.remote.server.max-channel-memory-size"") match { + case sz if sz < 0 ⇒ throw new IllegalArgumentException(""akka.remote.server.max-channel-memory-size is less than 0 bytes"") + case sz ⇒ sz + } + +- val MaxTotalMemorySize = getBytes(""akka.remote.server.max-total-memory-size"") match { ++ final val MaxTotalMemorySize = getBytes(""akka.remote.server.max-total-memory-size"") match { + case sz if sz < 0 ⇒ throw new IllegalArgumentException(""akka.remote.server.max-total-memory-size is less than 0 bytes"") + case sz ⇒ sz + } + + // TODO handle the system name right and move this to config file syntax +- val URI = ""akka://sys@"" + Hostname + "":"" + Port ++ final val URI = ""akka://sys@"" + Hostname + "":"" + Port","just verified that the bytecode generated with and without `final` is identical … (vals are always private final fields) +",f0bc2c7435c8898b695996b067d754407ab01f56 +376553,0,"Public class?""",2012-01-23 05:41:29,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/241#discussion_r376553,2012-01-23T16:41:29Z,2012-01-23T17:25:54Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/Locker.scala,,,,,1,"@@ -9,7 +9,12 @@ import akka.util.duration._ + import java.util.concurrent.ConcurrentHashMap + import akka.event.DeathWatch + +-class Locker(scheduler: Scheduler, period: Duration, val path: ActorPath, val deathWatch: DeathWatch) extends MinimalActorRef { ++class Locker(","Public class? +",9d7ed5eba16152d15269bf4f626260432359c0d4 +351948,0,"I think I prefer: import org.jboss.netty.akka.util.{ Timer, TimerTask, HashedWheelTimer, Timeout ⇒ HWTimeout }""",2012-01-13 08:27:39,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/214#discussion_r351948,2012-01-13T19:27:39Z,2012-01-16T09:16:09Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala,,,,,1,"@@ -5,7 +5,10 @@ + package akka.actor + + import java.util.concurrent.atomic.AtomicLong +-import org.jboss.netty.akka.util.{ TimerTask, HashedWheelTimer } ++import org.jboss.netty.akka.util.HashedWheelTimer ++import org.jboss.netty.akka.util.TimerTask ++import org.jboss.netty.akka.util.Timer ++import org.jboss.netty.akka.util.{ Timeout ⇒ HWTimeout }","I think I prefer: import org.jboss.netty.akka.util.{ Timer, TimerTask, HashedWheelTimer, Timeout ⇒ HWTimeout } +",a26876f5c6cc70fab15cc9f46620391d131c536f +309889,0,"changed to id""",2011-12-21 09:26:48,patriknw,akka,akka,,https://github.com/akka/akka-core/pull/182#discussion_r309889,2011-12-21T20:26:48Z,2011-12-21T22:47:22Z,patriknw,CONTRIBUTOR,akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala,,,,,1,"@@ -224,21 +225,21 @@ object ActorModelSpec { + } + } + +-abstract class ActorModelSpec extends AkkaSpec with DefaultTimeout { ++abstract class ActorModelSpec(config: String) extends AkkaSpec(config) with DefaultTimeout { + + import ActorModelSpec._ + +- def newTestActor(dispatcher: MessageDispatcher) = system.actorOf(Props[DispatcherActor].withDispatcher(dispatcher)) ++ def newTestActor(dispatcher: String) = system.actorOf(Props[DispatcherActor].withDispatcher(dispatcher)) + +- protected def newInterceptedDispatcher: MessageDispatcherInterceptor ++ protected def registerInterceptedDispatcher(): MessageDispatcherInterceptor + protected def dispatcherType: String + + ""A "" + dispatcherType must { + + ""must dynamically handle its own life cycle"" in { +- implicit val dispatcher = newInterceptedDispatcher ++ implicit val dispatcher = registerInterceptedDispatcher() + assertDispatcher(dispatcher)(stops = 0) +- val a = newTestActor(dispatcher) ++ val a = newTestActor(dispatcher.key)","changed to id +",ed2fb14dcf0120a6c126fe9c99038d897dbcdf0d +292805,2,"hmmm, weird...""",2011-12-14 00:56:37,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/147#discussion_r292805,2011-12-14T11:56:37Z,2011-12-14T11:56:37Z,viktorklang,CONTRIBUTOR,akka-docs/.history,,1.0,,,1,"@@ -0,0 +1 @@ ++exit","hmmm, weird... +",0af92f24400f1b05d1919be54dfd822037f0076f +20221,2,"This impl is weird. Uses system identityHashCode for hashCode AND equals?""",2011-04-17 23:42:26,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/73#discussion_r20221,2011-04-18T11:42:26Z,2011-04-18T11:42:26Z,viktorklang,CONTRIBUTOR,akka-stm/src/main/scala/stm/TransactionalSet.scala,,81.0,,,81,"@@ -0,0 +1,88 @@ ++package akka.stm ++ ++/** ++ * TransactionalSet : completely based on TransactionalMap ++ * @author - Dhananjay Nene ++ */ ++ ++/* ++ * TODO: Change package names in imports. This has been compiled against akka_2.8.0-1.0-M1.zip ++ */ ++ ++import scala.collection.mutable.HashSet ++import se.scalablesolutions.akka.stm.{Transactional, Ref} ++import se.scalablesolutions.akka.actor.{newUuid} ++ ++/** ++ * Transactional set that implements the mutable Set interface with an underlying Ref and HashSet. ++ */ ++ ++object TransactionalSet { ++ def apply[K]() = new TransactionalSet[K]() ++ ++ def apply[K](elems: K*) = new TransactionalSet(HashSet(elems: _*)) ++} ++ ++/** ++ * Transactional Set that implements the mutable Set interface with an underlying Ref and HashSet. ++ * ++ * From Scala you can use TSet as a shorter alias for TransactionalSet. ++ */ ++ ++class TransactionalSet[T](initialValue: HashSet[T]) extends Transactional with scala.collection.mutable.Set[T] { ++ def this() = this(HashSet[T]()) ++ ++ val uuid = newUuid.toString ++ ++ private[this] val ref = Ref(initialValue) ++ ++ override def -=(elem: T) = { ++ ref.set(ref.get - elem) ++ this ++ } ++ ++ override def +=(elem: T) = { ++ ref.set(ref.get + elem) ++ this ++ } ++ ++ override def += (elem1: T, elem2: T, elems: T*) = { ++ ref.set(ref.get + (elem1, elem2, elems: _*)) ++ this ++ } ++ ++ override def -= (elem1: T, elem2: T, elems: T*) = { ++ ref.set(ref.get - (elem1, elem2, elems: _*)) ++ this ++ } ++ ++ override def ++= (xs: TraversableOnce[T]) = { ++ ref.set(ref.get ++ xs) ++ this ++ } ++ ++ override def --= (xs: TraversableOnce[T]) = { ++ ref.set(ref.get -- xs) ++ this ++ } ++ ++ def iterator = ref.get.iterator ++ ++ override def elements: Iterator[T] = ref.get.iterator ++ ++ override def contains(elem: T): Boolean = ref.get.contains(elem) ++ ++ override def clear = ref.swap(HashSet[T]()) ++ ++ override def size: Int = ref.get.size ++ ++ override def hashCode: Int = System.identityHashCode(this); ++ ++ override def equals(other: Any): Boolean =","This impl is weird. Uses system identityHashCode for hashCode AND equals? +",95aff5ef78f4b8aca6f624f1402f3198acab056b +383593,2,"Really? You need to test that?""",2012-01-25 01:01:54,piotrga,akka,akka,,https://github.com/akka/akka-core/pull/245#discussion_r383593,2012-01-25T12:01:54Z,2012-01-25T12:01:54Z,piotrga,CONTRIBUTOR,akka-camel/src/test/scala/akka/camel/ProducerRegistryTest.scala,,22.0,,,22,"@@ -0,0 +1,59 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++ ++package akka.camel ++ ++import org.scalatest.matchers.MustMatchers ++import org.scalatest.WordSpec ++import akka.camel.TestSupport.SharedCamelSystem ++import akka.actor.Props ++import akka.util.duration._ ++ ++class ProducerRegistryTest extends WordSpec with MustMatchers with SharedCamelSystem { ++ ""A ProducerRegistry"" must { ++ ""register a started SendProcessor for the producer, which is stopped when the actor is stopped"" in { ++ val actorRef = system.actorOf(Props(behavior = ctx ⇒ { ++ case _ ⇒ {} ++ })) ++ val (endpoint, processor) = camel.registerProducer(actorRef, ""mock:mock"") ++ camel.awaitActivation(actorRef, 1 second) ++ processor.isStarted must be(true) ++ endpoint.getCamelContext must equal(camel.context)","Really? You need to test that? +",f6646051f79f6f3c7fb3214652bce46034efed9d +479638,1,"also, always have return types on your methods. Trust me, will save everyone involved a lot of headache and will add documentation.""",2012-02-22 22:41:28,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/350#discussion_r479638,2012-02-23T09:41:28Z,2012-03-06T19:30:29Z,viktorklang,CONTRIBUTOR,akka-amqp/src/main/scala/akka/amqp/AMQP.scala,,,,,1,"@@ -0,0 +1,461 @@ ++/** ++ * Copyright (C) 2009-2010 Scalable Solutions AB ++ */ ++ ++package akka.amqp ++ ++import com.rabbitmq.client.AMQP.BasicProperties ++import java.lang.{ String, IllegalArgumentException } ++import reflect.Manifest ++import akka.japi.Procedure ++import com.rabbitmq.client._ ++import ConnectionFactory._ ++import akka.actor.{ Address ⇒ _, _ } ++import akka.pattern.ask ++import akka.util.duration._ ++import akka.util.Timeout ++import akka.dispatch.Await ++import java.util.UUID ++ ++/** ++ * AMQP Actor API. Implements Connection, Producer and Consumer materialized as Actors. ++ * ++ * @see akka.amqp.ExampleSession ++ * ++ * @author Irmo Manie ++ * @author John Stanford (migration to Akka 2.0) ++ */ ++ ++object AMQP { ++ ++ implicit val timeout = Timeout(5 seconds) ++ ++ private lazy val system = ActorSystem(""AMQPSystem"") ++ ++ /** ++ * Parameters used to make the connection to the amqp broker. Uses the rabbitmq defaults. ++ */ ++ case class ConnectionParameters( ++ addresses: Array[Address] = Array(new Address(DEFAULT_HOST, DEFAULT_AMQP_PORT)), ++ username: String = DEFAULT_USER, ++ password: String = DEFAULT_PASS, ++ virtualHost: String = DEFAULT_VHOST, ++ initReconnectDelay: Long = 5000, ++ connectionCallback: Option[ActorRef] = None) { ++ ++ // Needed for Java API usage ++ def this() = this(Array(new Address(DEFAULT_HOST, DEFAULT_AMQP_PORT)), DEFAULT_USER, DEFAULT_PASS, DEFAULT_VHOST, 5000, None) ++ ++ // Needed for Java API usage ++ def this(addresses: Array[Address], username: String, password: String, virtualHost: String) = ++ this(addresses, username, password, virtualHost, 5000, None) ++ ++ // Needed for Java API usage ++ def this(addresses: Array[Address], username: String, password: String, virtualHost: String, initReconnectDelay: Long, connectionCallback: ActorRef) = ++ this(addresses, username, password, virtualHost, initReconnectDelay, Some(connectionCallback)) ++ ++ // Needed for Java API usage ++ def this(connectionCallback: ActorRef) = ++ this(Array(new Address(DEFAULT_HOST, DEFAULT_AMQP_PORT)), DEFAULT_USER, DEFAULT_PASS, DEFAULT_VHOST, 5000, Some(connectionCallback)) ++ ++ } ++ ++ /** ++ * Additional parameters for the channel ++ */ ++ case class ChannelParameters( ++ shutdownListener: Option[ShutdownListener] = None, ++ channelCallback: Option[ActorRef] = None, ++ prefetchSize: Int = 0) { ++ ++ // Needed for Java API usage ++ def this() = this(None, None) ++ ++ // Needed for Java API usage ++ def this(channelCallback: ActorRef) = this(None, Some(channelCallback)) ++ ++ // Needed for Java API usage ++ def this(shutdownListener: ShutdownListener, channelCallback: ActorRef) = ++ this(Some(shutdownListener), Some(channelCallback)) ++ } ++ ++ /** ++ * Declaration type used for either exchange or queue declaration ++ */ ++ sealed trait Declaration ++ case object NoActionDeclaration extends Declaration { ++ def getInstance() = this // Needed for Java API usage ++ } ++ case object PassiveDeclaration extends Declaration { ++ def getInstance() = this // Needed for Java API usage ++ } ++ case class ActiveDeclaration(durable: Boolean = false, autoDelete: Boolean = true, exclusive: Boolean = false) extends Declaration { ++ ++ // Needed for Java API usage ++ def this() = this(false, true, false) ++ ++ // Needed for Java API usage ++ def this(durable: Boolean, autoDelete: Boolean) = this(durable, autoDelete, false) ++ } ++ ++ /** ++ * Exchange specific parameters ++ */ ++ case class ExchangeParameters( ++ exchangeName: String, ++ exchangeType: ExchangeType = Topic, ++ exchangeDeclaration: Declaration = ActiveDeclaration(), ++ configurationArguments: Map[String, AnyRef] = Map.empty) { ++ ++ // Needed for Java API usage ++ def this(exchangeName: String) = ++ this(exchangeName, Topic, ActiveDeclaration(), Map.empty) ++ ++ // Needed for Java API usage ++ def this(exchangeName: String, exchangeType: ExchangeType) = ++ this(exchangeName, exchangeType, ActiveDeclaration(), Map.empty) ++ ++ // Needed for Java API usage ++ def this(exchangeName: String, exchangeType: ExchangeType, exchangeDeclaration: Declaration) = ++ this(exchangeName, exchangeType, exchangeDeclaration, Map.empty) ++ } ++ ++ /** ++ * Producer specific parameters ++ */ ++ case class ProducerParameters( ++ exchangeParameters: Option[ExchangeParameters] = None, ++ returnListener: Option[ReturnListener] = None, ++ channelParameters: Option[ChannelParameters] = None, ++ errorCallbackActor: Option[ActorRef] = None) { ++ def this() = this(None, None, None, None) ++ ++ // Needed for Java API usage ++ def this(exchangeParameters: ExchangeParameters) = ++ this(Some(exchangeParameters), None, None, None) ++ ++ // Needed for Java API usage ++ def this(exchangeParameters: ExchangeParameters, returnListener: ReturnListener) = ++ this(Some(exchangeParameters), Some(returnListener), None, None) ++ ++ // Needed for Java API usage ++ def this(exchangeParameters: ExchangeParameters, channelParameters: ChannelParameters) = ++ this(Some(exchangeParameters), None, Some(channelParameters), None) ++ ++ // Needed for Java API usage ++ def this(exchangeParameters: ExchangeParameters, returnListener: ReturnListener, channelParameters: ChannelParameters) = ++ this(Some(exchangeParameters), Some(returnListener), Some(channelParameters), None) ++ ++ // Needed for Java API usage ++ def this(exchangeParameters: ExchangeParameters, returnListener: ReturnListener, channelParameters: ChannelParameters, errorCallbackActor: ActorRef) = ++ this(Some(exchangeParameters), Some(returnListener), Some(channelParameters), Some(errorCallbackActor)) ++ ++ // Needed for Java API usage ++ def this(exchangeParameters: ExchangeParameters, channelParameters: ChannelParameters, errorCallbackActor: ActorRef) = ++ this(Some(exchangeParameters), None, Some(channelParameters), Some(errorCallbackActor)) ++ } ++ ++ /** ++ * Consumer specific parameters ++ */ ++ case class ConsumerParameters( ++ routingKey: String, ++ deliveryHandler: ActorRef, ++ queueName: Option[String] = None, ++ exchangeParameters: Option[ExchangeParameters] = None, ++ queueDeclaration: Declaration = ActiveDeclaration(), ++ selfAcknowledging: Boolean = true, ++ channelParameters: Option[ChannelParameters] = None) { ++ if (queueName.isEmpty) { ++ queueDeclaration match { ++ case ActiveDeclaration(true, _, _) ⇒ ++ throw new IllegalArgumentException(""A queue name is required when requesting a durable queue."") ++ case PassiveDeclaration ⇒ ++ throw new IllegalArgumentException(""A queue name is required when requesting passive declaration."") ++ case _ ⇒ () // ignore ++ } ++ } ++ ++ // Needed for Java API usage ++ def this(routingKey: String, deliveryHandler: ActorRef) = ++ this(routingKey, deliveryHandler, None, None, ActiveDeclaration(), true, None) ++ ++ // Needed for Java API usage ++ def this(routingKey: String, deliveryHandler: ActorRef, channelParameters: ChannelParameters) = ++ this(routingKey, deliveryHandler, None, None, ActiveDeclaration(), true, Some(channelParameters)) ++ ++ // Needed for Java API usage ++ def this(routingKey: String, deliveryHandler: ActorRef, selfAcknowledging: Boolean) = ++ this(routingKey, deliveryHandler, None, None, ActiveDeclaration(), selfAcknowledging, None) ++ ++ // Needed for Java API usage ++ def this(routingKey: String, deliveryHandler: ActorRef, selfAcknowledging: Boolean, channelParameters: ChannelParameters) = ++ this(routingKey, deliveryHandler, None, None, ActiveDeclaration(), selfAcknowledging, Some(channelParameters)) ++ ++ // Needed for Java API usage ++ def this(routingKey: String, deliveryHandler: ActorRef, queueName: String) = ++ this(routingKey, deliveryHandler, Some(queueName), None, ActiveDeclaration(), true, None) ++ ++ // Needed for Java API usage ++ def this(routingKey: String, deliveryHandler: ActorRef, queueName: String, queueDeclaration: Declaration, selfAcknowledging: Boolean, channelParameters: ChannelParameters) = ++ this(routingKey, deliveryHandler, Some(queueName), None, queueDeclaration, selfAcknowledging, Some(channelParameters)) ++ ++ // Needed for Java API usage ++ def this(routingKey: String, deliveryHandler: ActorRef, exchangeParameters: ExchangeParameters) = ++ this(routingKey, deliveryHandler, None, Some(exchangeParameters), ActiveDeclaration(), true, None) ++ ++ // Needed for Java API usage ++ def this(routingKey: String, deliveryHandler: ActorRef, exchangeParameters: ExchangeParameters, channelParameters: ChannelParameters) = ++ this(routingKey, deliveryHandler, None, Some(exchangeParameters), ActiveDeclaration(), true, Some(channelParameters)) ++ ++ // Needed for Java API usage ++ def this(routingKey: String, deliveryHandler: ActorRef, exchangeParameters: ExchangeParameters, selfAcknowledging: Boolean) = ++ this(routingKey, deliveryHandler, None, Some(exchangeParameters), ActiveDeclaration(), selfAcknowledging, None) ++ ++ // Needed for Java API usage ++ def this(routingKey: String, deliveryHandler: ActorRef, queueName: String, exchangeParameters: ExchangeParameters) = ++ this(routingKey, deliveryHandler, Some(queueName), Some(exchangeParameters), ActiveDeclaration(), true, None) ++ ++ // Needed for Java API usage ++ def this(routingKey: String, deliveryHandler: ActorRef, queueName: String, exchangeParameters: ExchangeParameters, queueDeclaration: Declaration) = ++ this(routingKey, deliveryHandler, Some(queueName), Some(exchangeParameters), queueDeclaration, true, None) ++ ++ // Needed for Java API usage ++ def this(routingKey: String, deliveryHandler: ActorRef, queueName: String, exchangeParameters: ExchangeParameters, queueDeclaration: Declaration, selfAcknowledging: Boolean) = ++ this(routingKey, deliveryHandler, Some(queueName), Some(exchangeParameters), queueDeclaration, selfAcknowledging, None) ++ ++ // Needed for Java API usage ++ def this(routingKey: String, deliveryHandler: ActorRef, queueName: String, exchangeParameters: ExchangeParameters, queueDeclaration: Declaration, selfAcknowledging: Boolean, channelParameters: ChannelParameters) = ++ this(routingKey, deliveryHandler, Some(queueName), Some(exchangeParameters), queueDeclaration, selfAcknowledging, Some(channelParameters)) ++ ++ // How about that for some overloading... huh? :P (yes, I know, there are still possibilities left...sue me!) ++ // Who said java is easy :( ++ } ++ ++ def newConnection(connectionParameters: ConnectionParameters = new ConnectionParameters()): ActorRef = { ++ ++ val connection = system.actorOf(Props(new FaultTolerantConnectionActor(connectionParameters)), ""amqp-connection-"" + UUID.randomUUID.toString) ++ connection ! Connect ++ connection ++ } ++ ++ def shutdownConnection(connection: ActorRef) = { ++ system.stop(connection) ++ } ++ ++ // Needed for Java API usage ++ def newConnection(): ActorRef = { ++ newConnection(new ConnectionParameters()) ++ } ++ ++ def newProducer(connection: ActorRef, producerParameters: ProducerParameters) = { ++ val p = connection ? ProducerRequest(producerParameters) ++ Await.result(p, timeout.duration).asInstanceOf[Option[ActorRef]]","also, always have return types on your methods. Trust me, will save everyone involved a lot of headache and will add documentation. +",e039c380c868b28285dab6fc313025d981ef022b +525841,0,"don't understand the above, why not just sender ! self""",2012-03-06 11:49:00,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/350#discussion_r525841,2012-03-06T22:49:00Z,2012-03-06T22:49:00Z,viktorklang,CONTRIBUTOR,akka-amqp/src/main/scala/akka/amqp/FaultTolerantChannelActor.scala,,69.0,,,69,"@@ -0,0 +1,188 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++ ++package akka.amqp ++ ++import collection.JavaConversions ++import java.lang.Throwable ++import akka.event.Logging ++import akka.pattern.{ ask, pipe } ++import com.rabbitmq.client.{ ShutdownSignalException, Channel, ShutdownListener } ++import scala.PartialFunction ++import akka.dispatch.{ Promise, ExecutionContext, Future } ++import akka.util.{ NonFatal, Timeout } ++import akka.actor.{ ActorRef, Status, Kill, Actor } ++ ++abstract private[amqp] class FaultTolerantChannelActor( ++ exchangeParameters: Option[ExchangeParameters], channelParameters: Option[ChannelParameters]) extends Actor { ++ ++ protected[amqp] var channel: Option[Future[Channel]] = None ++ implicit val sys = context.system ++ ++ val settings = Settings(context.system) ++ implicit val timeout = Timeout(settings.Timeout) ++ ++ val log = Logging(context.system, this) ++ ++ val shutdownListener = new ShutdownListener { ++ def shutdownCompleted(cause: ShutdownSignalException) = { ++ val replyTo = self ++ replyTo ! ChannelShutdown(cause) ++ } ++ } ++ ++ /** ++ * handle channel core and custom messages ++ */ ++ override def receive = channelMessageHandler orElse specificMessageHandler ++ ++ /** ++ * extending actors should implement custom message handling logic in their specificMessageHandler method ++ */ ++ def specificMessageHandler: PartialFunction[Any, Unit] ++ ++ /** ++ * defines the core channel message handlers. ++ */ ++ private def channelMessageHandler: PartialFunction[Any, Unit] = { ++ ++ /** ++ * a producer or consumer is requesting a channel, either because they are initially starting, or ++ * because the channel has unexpectedly shut down. the parent is the connection actor associated ++ * with this producer/consumer. it sends back a Future[Channel] or Failure if it can't be established. ++ */ ++ case Start ⇒ ++ val slf = context.self ++ val snd = context.sender ++ ++ context.parent ? ChannelRequest onComplete { ++ case Right(r) ⇒ slf ? r onComplete { ++ case Right(r) ⇒ snd ! r ++ case Left(f) ⇒ snd ! Status.Failure(f) ++ } ++ case Left(f) ⇒ slf ! Status.Failure(f) ++ } ++ case ch: Channel ⇒ ++ setupChannelInternal(ch) ++ val reply = self ++ sender ! reply","don't understand the above, why not just sender ! self +",e039c380c868b28285dab6fc313025d981ef022b +488570,0,"No need - as header is set by camel only if previous call failed""",2012-02-24 23:43:01,piotrga,akka,akka,,https://github.com/akka/akka-core/pull/344#discussion_r488570,2012-02-25T10:43:01Z,2012-03-20T12:17:26Z,piotrga,CONTRIBUTOR,akka-camel/src/test/scala/akka/camel/ConsumerIntegrationTest.scala,,153.0,,,1,"@@ -0,0 +1,159 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++ ++package akka.camel ++ ++import akka.actor._ ++import org.scalatest.matchers.MustMatchers ++import akka.util.duration._ ++import java.util.concurrent.TimeUnit._ ++import TestSupport._ ++import org.scalatest.WordSpec ++import org.apache.camel.model.RouteDefinition ++import org.apache.camel.builder.Builder ++import org.apache.camel.{ FailedToCreateRouteException, CamelExecutionException } ++import java.util.concurrent.{ ExecutionException, TimeUnit, TimeoutException, CountDownLatch } ++ ++class ConsumerIntegrationTest extends WordSpec with MustMatchers with NonSharedCamelSystem { ++ ++ ""Consumer must throw FailedToCreateRouteException, while awaiting activation, if endpoint is invalid"" in { ++ val actorRef = system.actorOf(Props(new TestActor(uri = ""some invalid uri""))) ++ ++ intercept[FailedToCreateRouteException] { ++ camel.awaitActivation(actorRef, timeout = 1 second) ++ } ++ } ++ ++ ""Consumer must support in-out messaging"" in { ++ start(new Consumer { ++ def endpointUri = ""direct:a1"" ++ protected def receive = { ++ case m: Message ⇒ sender ! ""received "" + m.bodyAs[String] ++ } ++ }) ++ camel.sendTo(""direct:a1"", msg = ""some message"") must be(""received some message"") ++ } ++ ++ ""Consumer must time-out if consumer is slow"" in { ++ val SHORT_TIMEOUT = 10 millis ++ val LONG_WAIT = 200 millis ++ ++ start(new Consumer { ++ override def replyTimeout = SHORT_TIMEOUT ++ ++ def endpointUri = ""direct:a3"" ++ protected def receive = { case _ ⇒ { Thread.sleep(LONG_WAIT.toMillis); sender ! ""done"" } } ++ }) ++ ++ val exception = intercept[CamelExecutionException] { ++ camel.sendTo(""direct:a3"", msg = ""some msg 3"") ++ } ++ exception.getCause.getClass must be(classOf[TimeoutException]) ++ } ++ ++ ""Consumer must process messages even after actor restart"" in { ++ val restarted = new CountDownLatch(1) ++ val consumer = start(new Consumer { ++ def endpointUri = ""direct:a2"" ++ ++ protected def receive = { ++ case ""throw"" ⇒ throw new Exception ++ case m: Message ⇒ sender ! ""received "" + m.bodyAs[String] ++ } ++ ++ override def postRestart(reason: Throwable) { ++ restarted.countDown() ++ } ++ }) ++ consumer ! ""throw"" ++ if (!restarted.await(1, SECONDS)) fail(""Actor failed to restart!"") ++ ++ val response = camel.sendTo(""direct:a2"", msg = ""xyz"") ++ response must be(""received xyz"") ++ } ++ ++ ""Consumer must unregister itself when stopped"" in { ++ val consumer = start(new TestActor()) ++ camel.awaitActivation(consumer, 1 second) ++ ++ camel.routeCount must be > (0) ++ ++ system.stop(consumer) ++ camel.awaitDeactivation(consumer, 1 second) ++ ++ camel.routeCount must be(0) ++ } ++ ++ ""Error passing consumer supports error handling through route modification"" in { ++ start(new ErrorThrowingConsumer(""direct:error-handler-test"") with ErrorPassing { ++ override def onRouteDefinition(rd: RouteDefinition) = { ++ rd.onException(classOf[Exception]).handled(true).transform(Builder.exceptionMessage).end ++ } ++ }) ++ camel.sendTo(""direct:error-handler-test"", msg = ""hello"") must be(""error: hello"") ++ } ++ ++ ""Error passing consumer supports redelivery through route modification"" in { ++ start(new FailingOnceConsumer(""direct:failing-once-concumer"") with ErrorPassing { ++ override def onRouteDefinition(rd: RouteDefinition) = { ++ rd.onException(classOf[Exception]).maximumRedeliveries(1).end ++ } ++ }) ++ camel.sendTo(""direct:failing-once-concumer"", msg = ""hello"") must be(""accepted: hello"") ++ } ++ ++ ""Consumer supports manual Ack"" in { ++ start(new ManualAckConsumer() { ++ def endpointUri = ""direct:manual-ack"" ++ protected def receive = { case _ ⇒ sender ! Ack } ++ }) ++ camel.template.asyncSendBody(""direct:manual-ack"", ""some message"").get(1, TimeUnit.SECONDS) must be(null) //should not timeout ++ } ++ ++ ""Consumer handles manual Ack failure"" in { ++ val someException = new Exception(""e1"") ++ start(new ManualAckConsumer() { ++ def endpointUri = ""direct:manual-ack"" ++ protected def receive = { case _ ⇒ sender ! Failure(someException) } ++ }) ++ ++ intercept[ExecutionException] { ++ camel.template.asyncSendBody(""direct:manual-ack"", ""some message"").get(1, TimeUnit.SECONDS) ++ }.getCause.getCause must be(someException) ++ } ++ ++ ""Consumer should time-out, if manual Ack not received within replyTimeout and should give a human readable error message"" in { ++ start(new ManualAckConsumer() { ++ override def replyTimeout = 10 millis ++ def endpointUri = ""direct:manual-ack"" ++ protected def receive = { case _ ⇒ } ++ }) ++ ++ intercept[ExecutionException] { ++ camel.template.asyncSendBody(""direct:manual-ack"", ""some message"").get(1, TimeUnit.SECONDS) ++ }.getCause.getCause.getMessage must include(""Failed to get Ack"") ++ } ++} ++ ++class ErrorThrowingConsumer(override val endpointUri: String) extends Consumer { ++ def receive = { ++ case msg: Message ⇒ throw new Exception(""error: %s"" format msg.body) ++ } ++} ++ ++class FailingOnceConsumer(override val endpointUri: String) extends Consumer { ++ ++ def receive = { ++ case msg: Message ⇒ ++ if (msg.headerAs[Boolean](""CamelRedelivered"").getOrElse(false)) ++ sender ! (""accepted: %s"" format msg.body) ++ else ++ throw new Exception(""rejected: %s"" format msg.body)","No need - as header is set by camel only if previous call failed +",f74616f828d3e31724d768dd86ce05af85d97ade +438782,0,"what happens if negative or 0?""",2012-02-10 06:30:34,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/323#discussion_r438782,2012-02-10T17:30:34Z,2012-02-10T17:30:34Z,viktorklang,CONTRIBUTOR,akka-zeromq/src/main/resources/reference.conf,,16.0,,,15,"@@ -12,6 +12,9 @@ akka { + # The default timeout for a poll on the actual zeromq socket. + poll-timeout = 100ms + ++ # Timeout for creating a new socket ++ new-socket-timeout = 5s","what happens if negative or 0? +",e017aeef0826fc99722b74551f336d1751f0e884 +419031,0,"here, too""",2012-02-06 04:04:26,rkuhn,akka,akka,,https://github.com/akka/akka-core/pull/307#discussion_r419031,2012-02-06T15:04:26Z,2012-02-28T09:22:30Z,rkuhn,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/Stash.scala,,,,,1,"@@ -0,0 +1,97 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++package akka.actor ++ ++import akka.dispatch.{ Envelope, DequeBasedMessageQueue } ++ ++/** ++ * The `Stash` trait enables an actor to temporarily stash away messages that can not or ++ * should not be handled using the actor's current behavior. ++ *

++ * Example: ++ *

++ *    class ActorWithProtocol extends Actor with Stash {
++ *      def receive = {
++ *        case ""open"" ⇒
++ *          unstashAll {
++ *            case ""write"" ⇒ // do writing...
++ *            case ""close"" ⇒
++ *              unstashAll()
++ *              context.unbecome()
++ *            case msg ⇒ stash()
++ *          }
++ *        case ""done"" ⇒ // done
++ *        case msg    ⇒ stash()
++ *      }
++ *    }
++ *  
++ * ++ * Note that the `Stash` trait can only be used together with actors that have a deque-based ++ * mailbox. Actors can be configured to use a deque-based mailbox using a configuration like ++ * the following: ++ *
++ *  akka {
++ *    actor {
++ *      default-dispatcher {
++ *        mailboxType = ""akka.dispatch.UnboundedDequeBasedMailbox""
++ *      }
++ *    }
++ *  }
++ *  
++ */ ++trait Stash { ++ thisActor: Actor ⇒ ++ ++ /* The private stash of the actor. It is only accessible using `stash()` and ++ * `unstashAll()`. ++ */ ++ private[this] var theStash = Vector.empty[Envelope] ++ ++ /* The actor's deque-based message queue. ++ * `mailbox.queue` is the underlying `Deque`. ++ */ ++ private[this] val mailbox: DequeBasedMessageQueue = {","here, too +",8ea949857b39388ac25bdc08df7feee3757f3ee9 +371286,0,"I'd still recommend having this final and calling the other with Duration.Inf, then the implementation of that can deal with Duration.Inf as it wants""",2012-01-20 03:41:46,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/238#discussion_r371286,2012-01-20T14:41:46Z,2012-01-20T17:39:49Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorSystem.scala,,256.0,,,79,"@@ -224,18 +229,39 @@ abstract class ActorSystem extends ActorRefFactory { + def dispatcher: MessageDispatcher + + /** +- * Register a block of code to run after all actors in this actor system have +- * been stopped. Multiple code blocks may be registered by calling this method multiple times; there is no +- * guarantee that they will be executed in a particular order. ++ * Register a block of code (callback) to run after all actors in this actor system have ++ * been stopped. Multiple code blocks may be registered by calling this method multiple times. ++ * The callbacks will be run sequentilly in reverse order of registration, i.e. ++ * last registration is run first. ++ * ++ * Callbacks registered after that the shutdown process has started will likely not be run. + */ +- def registerOnTermination[T](code: ⇒ T) ++ def registerOnTermination[T](code: ⇒ T): Unit + + /** +- * Register a block of code to run after all actors in this actor system have +- * been stopped. Multiple code blocks may be registered by calling this method multiple times; there is no +- * guarantee that they will be executed in a particular order (Java API). ++ * Register a block of code (callback) to run after all actors in this actor system have ++ * been stopped. Multiple code blocks may be registered by calling this method multiple times. ++ * The callbacks will be run sequentilly in reverse order of registration, i.e. ++ * last registration is run first. ++ * ++ * Callbacks registered after that the shutdown process has started will likely not be run. ++ * ++ * Java API + */ +- def registerOnTermination(code: Runnable) ++ def registerOnTermination(code: Runnable): Unit ++ ++ /** ++ * Block current thread until the system has been shutdown, or the specified ++ * timeout has elapsed. This will block until after all on termination ++ * callbacks have been run. ++ */ ++ def awaitTermination(timeout: Duration): Unit ++ ++ /** ++ * Block current thread until the system has been shutdown. This will ++ * block until after all on termination callbacks have been run. ++ */ ++ def awaitTermination(): Unit","I'd still recommend having this final and calling the other with Duration.Inf, then the implementation of that can deal with Duration.Inf as it wants +",a4e2b5a51140c721034bb8b33f06d0213985deb1 +366612,1,"player handlers also? thanks, I'm happy""",2012-01-19 00:06:13,patriknw,akka,akka,,https://github.com/akka/akka-core/pull/225#discussion_r366612,2012-01-19T11:06:13Z,2012-01-20T09:27:03Z,patriknw,CONTRIBUTOR,akka-zeromq/src/main/scala/akka/zeromq/ConcurrentSocketActor.scala,,,,,1,"@@ -0,0 +1,232 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++package akka.zeromq ++ ++import org.zeromq.ZMQ.{ Socket, Poller } ++import org.zeromq.{ ZMQ ⇒ JZMQ } ++import akka.actor._ ++import akka.dispatch.{ Promise, Future } ++import akka.event.Logging ++import akka.util.duration._ ++ ++private[zeromq] sealed trait PollLifeCycle ++private[zeromq] case object NoResults extends PollLifeCycle ++private[zeromq] case object Results extends PollLifeCycle ++private[zeromq] case object Closing extends PollLifeCycle ++ ++private[zeromq] class ConcurrentSocketActor(params: Seq[SocketOption]) extends Actor { ++ ++ private val noBytes = Array[Byte]() ++ private val zmqContext = { ++ params find (_.isInstanceOf[Context]) map (_.asInstanceOf[Context]) getOrElse new Context(1) ++ } ++ private lazy val deserializer = deserializerFromParams ++ private lazy val socket: Socket = socketFromParams ++ private lazy val poller: Poller = zmqContext.poller ++ private val log = Logging(context.system, this) ++ ++ private case object Poll ++ private case object ReceiveFrames ++ private case object ClearPoll ++ private case class PollError(ex: Throwable) ++ ++ private def handleConnectionMessages: Receive = { ++ case Send(frames) ⇒ { ++ sendFrames(frames) ++ pollAndReceiveFrames() ++ } ++ case ZMQMessage(frames) ⇒ { ++ sendFrames(frames) ++ pollAndReceiveFrames() ++ } ++ case Connect(endpoint) ⇒ { ++ socket.connect(endpoint) ++ notifyListener(Connecting) ++ pollAndReceiveFrames() ++ } ++ case Bind(endpoint) ⇒ { ++ socket.bind(endpoint) ++ pollAndReceiveFrames() ++ } ++ case Subscribe(topic) ⇒ { ++ socket.subscribe(topic.toArray) ++ pollAndReceiveFrames() ++ } ++ case Unsubscribe(topic) ⇒ { ++ socket.unsubscribe(topic.toArray) ++ pollAndReceiveFrames() ++ } ++ } ++ ++ private def handleSocketOption: Receive = { ++ case Linger(value) ⇒ socket.setLinger(value) ++ case ReconnectIVL(value) ⇒ socket.setReconnectIVL(value) ++ case Backlog(value) ⇒ socket.setBacklog(value) ++ case ReconnectIVLMax(value) ⇒ socket.setReconnectIVLMax(value) ++ case MaxMsgSize(value) ⇒ socket.setMaxMsgSize(value) ++ case SndHWM(value) ⇒ socket.setSndHWM(value) ++ case RcvHWM(value) ⇒ socket.setRcvHWM(value) ++ case HWM(value) ⇒ socket.setHWM(value) ++ case Swap(value) ⇒ socket.setSwap(value) ++ case Affinity(value) ⇒ socket.setAffinity(value) ++ case Identity(value) ⇒ socket.setIdentity(value) ++ case Rate(value) ⇒ socket.setRate(value) ++ case RecoveryInterval(value) ⇒ socket.setRecoveryInterval(value) ++ case MulticastLoop(value) ⇒ socket.setMulticastLoop(value) ++ case MulticastHops(value) ⇒ socket.setMulticastHops(value) ++ case ReceiveTimeOut(value) ⇒ socket.setReceiveTimeOut(value) ++ case SendTimeOut(value) ⇒ socket.setSendTimeOut(value) ++ case SendBufferSize(value) ⇒ socket.setSendBufferSize(value) ++ case ReceiveBufferSize(value) ⇒ socket.setReceiveBufferSize(value) ++ case Linger ⇒ sender ! socket.getLinger ++ case ReconnectIVL ⇒ sender ! socket.getReconnectIVL ++ case Backlog ⇒ sender ! socket.getBacklog ++ case ReconnectIVLMax ⇒ sender ! socket.getReconnectIVLMax ++ case MaxMsgSize ⇒ sender ! socket.getMaxMsgSize ++ case SndHWM ⇒ sender ! socket.getSndHWM ++ case RcvHWM ⇒ sender ! socket.getRcvHWM ++ case Swap ⇒ sender ! socket.getSwap ++ case Affinity ⇒ sender ! socket.getAffinity ++ case Identity ⇒ sender ! socket.getIdentity ++ case Rate ⇒ sender ! socket.getRate ++ case RecoveryInterval ⇒ sender ! socket.getRecoveryInterval ++ case MulticastLoop ⇒ sender ! socket.hasMulticastLoop ++ case MulticastHops ⇒ sender ! socket.getMulticastHops ++ case ReceiveTimeOut ⇒ sender ! socket.getReceiveTimeOut ++ case SendTimeOut ⇒ sender ! socket.getSendTimeOut ++ case SendBufferSize ⇒ sender ! socket.getSendBufferSize ++ case ReceiveBufferSize ⇒ sender ! socket.getReceiveBufferSize ++ case ReceiveMore ⇒ sender ! socket.hasReceiveMore ++ case FileDescriptor ⇒ sender ! socket.getFD ++ } ++ ++ private def internalMessage: Receive = { ++ case Poll ⇒ { ++ currentPoll = None ++ pollAndReceiveFrames() ++ } ++ case ReceiveFrames ⇒ { ++ receiveFrames() match { ++ case Seq() ⇒ ++ case frames ⇒ notifyListener(deserializer(frames)) ++ } ++ self ! Poll ++ } ++ case ClearPoll ⇒ currentPoll = None ++ case PollError(ex) ⇒ { ++ log.error(ex, ""There was a problem polling the zeromq socket"") ++ self ! Poll ++ } ++ } ++ ++ override def receive: Receive = handleConnectionMessages orElse handleSocketOption orElse internalMessage ++ ++ override def preStart { ++ setupSocket() ++ poller.register(socket, Poller.POLLIN) ++ setupConnection() ++ } ++ ++ private def setupConnection() { ++ params filter (_.isInstanceOf[SocketConnectOption]) foreach { self ! _ } ++ params filter (_.isInstanceOf[PubSubOption]) foreach { self ! _ } ++ } ++ ++ private def socketFromParams() = { ++ require(ZeroMQExtension.check[SocketType.ZMQSocketType](params), ""A socket type is required"") ++ (params ++ find (_.isInstanceOf[SocketType.ZMQSocketType]) ++ map (t ⇒ zmqContext.socket(t.asInstanceOf[SocketType.ZMQSocketType])) get) ++ } ++ ++ private def deserializerFromParams = { ++ params find (_.isInstanceOf[Deserializer]) map (_.asInstanceOf[Deserializer]) getOrElse new ZMQMessageDeserializer ++ } ++ ++ private def setupSocket() = { ++ params foreach { ++ case _: SocketConnectOption | _: PubSubOption | _: SocketMeta ⇒ // ignore, handled differently ++ case m ⇒ self ! m ++ } ++ } ++ ++ override def postStop { ++ try { ++ poller.unregister(socket) ++ currentPoll foreach { _ complete Right(Closing) } ++ if (socket != null) socket.close ++ } finally { ++ notifyListener(Closed) ++ } ++ } ++ ++ private def sendFrames(frames: Seq[Frame]) { ++ def sendBytes(bytes: Seq[Byte], flags: Int) = socket.send(bytes.toArray, flags) ++ val iter = frames.iterator ++ while (iter.hasNext) { ++ val payload = iter.next.payload ++ val flags = if (iter.hasNext) JZMQ.SNDMORE else 0 ++ sendBytes(payload, flags) ++ } ++ } ++ ++ private var currentPoll: Option[Promise[PollLifeCycle]] = None ++ private def pollAndReceiveFrames() { ++ if (currentPoll.isEmpty) currentPoll = newEventLoop ++ } ++ ++ private lazy val eventLoopDispatcher = {","why lazy? +",05e4af750081aeb757dab23c5a9885949ad901ea +362298,0,"Might want to include some more debug info about which actorref didn't manage to activate within how long.""",2012-01-18 00:03:26,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/217#discussion_r362298,2012-01-18T11:03:26Z,2012-01-18T16:57:17Z,viktorklang,CONTRIBUTOR,akka-camel/src/main/scala/akka/camel/Activation.scala,,53.0,,,53,"@@ -0,0 +1,54 @@ ++package akka.camel ++ ++import internal._ ++import java.util.concurrent.TimeoutException ++import akka.util.{Timeout, Duration} ++import akka.dispatch.Future ++import akka.actor.{ActorSystem, Props, ActorRef} ++ ++trait Activation{ ++ import akka.dispatch.Await ++ ++ val actorSystem : ActorSystem ++ private[camel] val activationTracker = actorSystem.actorOf(Props[ActivationTracker]) ++ ++ def activationFutureFor(actor: ActorRef, timeout: Duration): Future[ActorRef] = { ++ (activationTracker ?(AwaitActivation(actor), Timeout(timeout))).map[ActorRef]{ ++ case EndpointActivated(_) => actor ++ case EndpointFailedToActivate(_, cause) => throw cause ++ } ++ } ++ ++ /** ++ * Awaits for actor to be activated. ++ */ ++ def awaitActivation(actor: ActorRef, timeout: Duration): ActorRef = { ++ try{ ++ Await.result(activationFutureFor(actor, timeout), timeout) ++ }catch { ++ case e: TimeoutException => throw new ActivationTimeoutException ++ } ++ } ++ ++ def deactivationFutureFor(actor: ActorRef, timeout: Duration): Future[Unit] = { ++ (activationTracker ?(AwaitDeActivation(actor), Timeout(timeout))).map[Unit]{ ++ case EndpointDeActivated(_) => {} ++ case EndpointFailedToDeActivate(_, cause) => throw cause ++ } ++ } ++ ++ def awaitDeactivation(actor: ActorRef, timeout: Duration) { ++ try{ ++ Await.result(deactivationFutureFor(actor, timeout), timeout) ++ }catch { ++ case e: TimeoutException => throw new DeActivationTimeoutException ++ } ++ } ++ ++} ++ ++ ++ ++ ++class DeActivationTimeoutException extends RuntimeException(""Timed out while waiting for de-activation."")","Might want to include some more debug info about which actorref didn't manage to activate within how long. +",457354db8ba6b42dbacc246c11f0ff15e38ebab4 +362702,2,"This code above smells weird""",2012-01-18 02:07:57,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/217#discussion_r362702,2012-01-18T13:07:57Z,2012-01-18T16:57:19Z,viktorklang,CONTRIBUTOR,akka-camel/src/main/scala/akka/camel/internal/component/ActorComponent.scala,,170.0,,,1,"@@ -0,0 +1,303 @@ ++package akka.camel.internal.component ++ ++/** ++ * Copyright (C) 2009-2010 Scalable Solutions AB ++ */ ++ ++import java.util.{Map => JMap} ++ ++import org.apache.camel._ ++import org.apache.camel.impl.{DefaultProducer, DefaultEndpoint, DefaultComponent} ++ ++import akka.actor._ ++ ++import scala.reflect.BeanProperty ++import akka.dispatch.Await ++import akka.util.{Duration, Timeout} ++import akka.util.duration._ ++import akka.camel.{Camel, CamelExchangeAdapter, Ack, Failure, Message, BlockingOrNot, Blocking, NonBlocking} ++import java.util.concurrent.TimeoutException ++ ++private[camel] case class Path(actorPath: String) { ++ require(actorPath != null) ++ require(actorPath.length() > 0) ++ def toCamelPath = ""actor://path:%s"" format actorPath ++} ++ ++private[camel] object Path{ ++ def apply(actorRef: ActorRef) = new Path(actorRef.path.toString) ++ def fromCamelPath(camelPath : String) = camelPath match { ++ case id if id startsWith ""path:"" => new Path(id substring 5) ++ case _ => throw new IllegalArgumentException(""Invalid path: [%s] - should be path:"" format camelPath) ++ } ++} ++ ++ ++ ++/** ++ * Camel component for sending messages to and receiving replies from (untyped) actors. ++ * ++ * @see akka.camel.component.ActorEndpoint ++ * @see akka.camel.component.ActorProducer ++ * ++ * @author Martin Krasser ++ */ ++class ActorComponent(camel : Camel) extends DefaultComponent { ++ def createEndpoint(uri: String, remaining: String, parameters: JMap[String, Object]): ActorEndpoint = { ++ val path = Path.fromCamelPath(remaining) ++ new ActorEndpoint(uri, this, path, camel) ++ } ++} ++ ++ ++/** ++ * TODO fix the doc to be consistent with implementation ++ * Camel endpoint for sending messages to and receiving replies from (untyped) actors. Actors ++ * are referenced using actor endpoint URIs of the following format: ++ * actor:, ++ * actor:id:[] and ++ * actor:uuid:[], ++ * where refers to ActorRef.id and ++ * refers to the String-representation od ActorRef.uuid. In URIs that contain ++ * id: or uuid:, an actor identifier (id or uuid) is optional. In this ++ * case, the in-message of an exchange produced to this endpoint must contain a message header ++ * with name CamelActorIdentifier and a value that is the target actor's identifier. ++ * If the URI contains an actor identifier, a message with a CamelActorIdentifier ++ * header overrides the identifier in the endpoint URI. ++ * ++ * @see akka.camel.component.ActorComponent ++ * @see akka.camel.component.ActorProducer ++ ++ * @author Martin Krasser ++ */ ++class ActorEndpoint(uri: String, ++ comp: ActorComponent, ++ val path: Path, ++ camel : Camel) extends DefaultEndpoint(uri, comp) with ActorEndpointConfig{ ++ ++ ++ ++ /** ++ * @throws UnsupportedOperationException ++ */ ++ def createConsumer(processor: Processor): org.apache.camel.Consumer = ++ throw new UnsupportedOperationException(""actor consumer not supported yet"") ++ ++ /** ++ * Creates a new ActorProducer instance initialized with this endpoint. ++ */ ++ def createProducer: ActorProducer = new ActorProducer(this, camel) ++ ++ /** ++ * Returns true. ++ */ ++ def isSingleton: Boolean = true ++} ++ ++trait ActorEndpointConfig{ ++ def getEndpointUri : String ++ def path : Path ++ /** ++ * When endpoint is outCapable (can produce responses) outTimeout is the maximum time ++ * the endpoint can take to send the response back. It defaults to Int.MaxValue seconds. ++ * It can be overwritten by setting @see blocking property ++ */ ++ @BeanProperty var outTimeout: Duration = Int.MaxValue seconds ++ ++ ++ /** ++ * Whether to block caller thread during two-way message exchanges with (untyped) actors. This is ++ * set via the blocking=true|false endpoint URI parameter. Default value is ++ * false. ++ */ ++ @BeanProperty var blocking: BlockingOrNot = NonBlocking ++ ++ /** TODO fix it ++ * Whether to auto-acknowledge one-way message exchanges with (untyped) actors. This is ++ * set via the blocking=true|false endpoint URI parameter. Default value is ++ * true. When set to true consumer actors need to additionally ++ * call Consumer.ack within Actor.receive. ++ */ ++ @BeanProperty var autoack: Boolean = true ++} ++ ++/** ++ * Sends the in-message of an exchange to an (untyped) actor, identified by an ++ * actor endpoint URI or by a CamelActorIdentifier message header. ++ *
    ++ *
  • If the exchange pattern is out-capable and blocking is set to ++ * true then the producer waits for a reply, using the !! operator.
  • ++ *
  • If the exchange pattern is out-capable and blocking is set to ++ * false then the producer sends the message using the ! operator, together ++ * with a callback handler. The callback handler is an ActorRef that can be ++ * used by the receiving actor to asynchronously reply to the route that is sending the ++ * message.
  • ++ *
  • If the exchange pattern is in-only then the producer sends the message using the ++ * ! operator.
  • ++ *
++ * ++ * @see akka.camel.component.ActorComponent ++ * @see akka.camel.component.ActorEndpoint ++ * ++ * @author Martin Krasser ++ */ ++class ActorProducer(val ep: ActorEndpoint, camel: Camel) extends DefaultProducer(ep) with AsyncProcessor { ++ def process(exchange: Exchange) {new TestableProducer(ep, camel).process(new CamelExchangeAdapter(exchange))} ++ def process(exchange: Exchange, callback: AsyncCallback) = new TestableProducer(ep, camel).process(new CamelExchangeAdapter(exchange), callback) ++} ++ ++//TODO needs to know about ActorSystem instead of ConsumerRegistry. why is it called TestableProducer? ++// re: I'd rather keep the abstraction layer for now and let the Camel class delegate ++class TestableProducer(config : ActorEndpointConfig, camel : Camel) { ++ ++ private lazy val path = config.path ++ ++ def process(exchange: CamelExchangeAdapter) { ++ if (exchange.isOutCapable) ++ sendSync(exchange, config.outTimeout, forwardResponseTo(exchange)) ++ else ++ fireAndForget(exchange) ++ } ++ ++ def process(exchange: CamelExchangeAdapter, callback: AsyncCallback): Boolean = { ++ def notifyDoneSynchronously[A](a:A = null) = callback.done(true) ++ def notifyDoneAsynchronously[A](a:A = null) = callback.done(false) ++ val DoneSync = true ++ val DoneAsync = false","This code above smells weird +",457354db8ba6b42dbacc246c11f0ff15e38ebab4 +363051,0,"So why is it a WeakHashMap if you already use the DeathWatch?""",2012-01-18 04:00:41,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/217#discussion_r363051,2012-01-18T15:00:41Z,2012-01-18T16:57:21Z,viktorklang,CONTRIBUTOR,akka-camel/src/main/scala/akka/camel/internal/ActivationTracker.scala,,80.0,,,80,"@@ -0,0 +1,80 @@ ++package akka.camel.internal ++ ++import akka.actor._ ++import akka.camel._ ++import collection.mutable.WeakHashMap ++import akka.event.Logging.Warning ++ ++ ++ ++class ActivationTracker extends Actor{ ++ ++ val activations = new WeakHashMap[ActorRef, ActivationStateMachine] ++ ++ class ActivationStateMachine { ++ private[this] var awaitingActivation : List[ActorRef] = Nil ++ private[this] var awaitingDeActivation : List[ActorRef] = Nil ++ private[this] var activationFailure : Option[Throwable] = None ++ ++ var receive : Receive = notActivated ++ ++ def notActivated : Receive = { ++ case AwaitActivation(ref) => awaitingActivation ::= sender ++ case AwaitDeActivation(ref) => awaitingDeActivation ::= sender ++ ++ case msg @ EndpointActivated(ref) => { ++ migration.Migration.EventHandler.debug(ref+"" activated"") ++ awaitingActivation.foreach(_ ! msg) ++ awaitingActivation = Nil ++ receive = activated ++ } ++ ++ case EndpointFailedToActivate(ref, cause) => { ++ migration.Migration.EventHandler.debug(ref+"" failed to activate"") ++ activationFailure = Option(cause) ++ awaitingActivation.foreach(_ ! EndpointFailedToActivate(ref, cause)) ++ awaitingActivation = Nil ++ receive = failedToActivate ++ } ++ } ++ ++ def activated : Receive = { ++ case AwaitActivation(ref) => sender ! EndpointActivated(ref) ++ case AwaitDeActivation(ref) => awaitingDeActivation ::= sender ++ case EndpointDeActivated(ref) => { ++ awaitingDeActivation foreach (_ ! EndpointDeActivated(ref)) ++ awaitingDeActivation = Nil ++ context.stop(self) ++ } ++ case msg : EndpointFailedToDeActivate => { ++ awaitingDeActivation foreach (_ ! msg) ++ awaitingDeActivation = Nil ++ } ++ } ++ ++ def failedToActivate : Receive = { ++ case AwaitActivation(ref) => sender ! EndpointFailedToActivate(ref, activationFailure.get) ++ case AwaitDeActivation(ref) => sender ! EndpointFailedToActivate(ref, activationFailure.get) ++ } ++ ++ } ++ ++ override def preStart() { ++ context.system.eventStream.subscribe(self, classOf[ActivationMessage]) ++ } ++ ++ override def receive = { ++ case msg @ ActivationMessage(ref) =>{ ++ try{ ++ activations.getOrElseUpdate(ref, new ActivationStateMachine).receive(msg)","So why is it a WeakHashMap if you already use the DeathWatch? +",457354db8ba6b42dbacc246c11f0ff15e38ebab4 +335896,0,"What if the collections' size is Integer.MAX_VALUE?""",2012-01-08 21:56:02,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/204#discussion_r335896,2012-01-09T08:56:02Z,2012-01-09T08:56:02Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/routing/Routing.scala,,253.0,,,34,"@@ -229,10 +231,28 @@ trait RoundRobinLike { this: RouterConfig ⇒ + def createRoute(props: Props, context: ActorContext, ref: RoutedActorRef): Route = { + createAndRegisterRoutees(props, context, nrOfInstances, routees) + +- val next = new AtomicInteger(0) ++ val next = new AtomicInteger(-1) + + def getNext(): ActorRef = { +- ref.routees(next.getAndIncrement % ref.routees.size) ++ val _routees = ref.routees ++ val size = _routees.size ++ ++ @tailrec ++ def reduce(n: Int) { ++ val safetyValue = if (size >= 10000) size else (size * 100000) ++ if (n >= safetyValue) { ++ // decrease with multiple of the modulus, so that it doesn't change the modulus value ++ val newValue = n - safetyValue ++ next.compareAndSet(n, newValue) ++ reduce(next.get) ++ } ++ } ++ ++ val n = next.incrementAndGet() ++ // make sure we don't exceed Int.MaxValue ++ reduce(n)","What if the collections' size is Integer.MAX_VALUE? +",3099a074e5feec91733f475000f2e8ab03d6ebbb +309244,0,"On Wed, Dec 21, 2011 at 5:24 PM, viktorklang < reply@reply.github.com > wrote: > > > > // FIXME: Dispatchers registered here are are not removed, see ticket > #1494 > > - private val dispatchers = new ConcurrentHashMap[String, > MessageDispatcher] > """,2011-12-21 05:26:54,patriknw,akka,akka,,https://github.com/akka/akka-core/pull/182#discussion_r309244,2011-12-21T16:26:54Z,2011-12-21T22:47:22Z,patriknw,CONTRIBUTOR,akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala,,65.0,,,1,"@@ -67,15 +68,18 @@ class Dispatchers(val settings: ActorSystem.Settings, val prerequisites: Dispatc + if (settings.MailboxCapacity < 1) UnboundedMailbox() + else BoundedMailbox(settings.MailboxCapacity, settings.MailboxPushTimeout) + +- val defaultDispatcherConfig = settings.config.getConfig(""akka.actor.default-dispatcher"") ++ val defaultDispatcherConfig = { ++ val key = ""akka.actor.default-dispatcher"" ++ keyConfig(key).withFallback(settings.config.getConfig(key)) ++ } + +- lazy val defaultGlobalDispatcher: MessageDispatcher = +- from(defaultDispatcherConfig) getOrElse { +- throw new ConfigurationException(""Wrong configuration [akka.actor.default-dispatcher]"") +- } ++ private lazy val defaultDispatcherConfigurator: MessageDispatcherConfigurator = ++ configuratorFrom(defaultDispatcherConfig) ++ ++ lazy val defaultGlobalDispatcher: MessageDispatcher = defaultDispatcherConfigurator.dispatcher() + + // FIXME: Dispatchers registered here are are not removed, see ticket #1494 +- private val dispatchers = new ConcurrentHashMap[String, MessageDispatcher] ++ private val dispatcherConfigurators = new ConcurrentHashMap[String, MessageDispatcherConfigurator] + + /** + * Returns a dispatcher as specified in configuration, or if not defined it uses","On Wed, Dec 21, 2011 at 5:24 PM, viktorklang < +reply@reply.github.com + +> wrote: +> +> > // FIXME: Dispatchers registered here are are not removed, see ticket +> > #1494 +> > - private val dispatchers = new ConcurrentHashMap[String, +> > MessageDispatcher] +> > - private val dispatcherConfigurators = new ConcurrentHashMap[String, +> > MessageDispatcherConfigurator] +> > +> > /** +> > - Returns a dispatcher as specified in configuration, or if not +> > defined it uses +> +> No, my point was, if I say that ""foo"" should be my dispatcher, and there +> is no ""foo"" registered, and it falls back to the default, I want a WARNING +> +> Alright, I have another point, but I'll change it to Warning. +> +> --- +> +> Reply to this email directly or view it on GitHub: +> https://github.com/jboner/akka/pull/182/files#r309229 + +## + +Patrik Nordwall +Typesafe http://typesafe.com/ - Enterprise-Grade Scala from the Experts +Twitter: @patriknw +",ed2fb14dcf0120a6c126fe9c99038d897dbcdf0d +269632,0,"no, the only thing which must be protected against concurrent enqueue() (which is a read) is shutdown().""",2011-12-05 01:29:19,rkuhn,akka,akka,,https://github.com/akka/akka-core/pull/119#discussion_r269632,2011-12-05T12:29:19Z,2011-12-05T21:48:28Z,rkuhn,CONTRIBUTOR,akka-actor/src/main/java/org/jboss/netty/akka/util/HashedWheelTimer.java,,184.0,,,16,"@@ -181,12 +181,17 @@ private static int normalizeTicksPerWheel(int ticksPerWheel) { + * {@linkplain #stop() stopped} already + */ + public synchronized void start() { +- if (shutdown.get()) { +- throw new IllegalStateException(""cannot be started once stopped""); +- } ++ lock.readLock().lock();","no, the only thing which must be protected against concurrent enqueue() (which is a read) is shutdown(). +",9d7597c7282711889d74bd9b4d7bdae5ea254104 +436872,0,"I understand that, but what about DynamicAccess or DynamicClassMaster. Looking at the signatures it is all about fqcn strings. PropertyMaster can be a manager that handles just about anything.""",2012-02-09 21:14:51,patriknw,akka,akka,,https://github.com/akka/akka-core/pull/316#discussion_r436872,2012-02-10T08:14:51Z,2012-02-10T13:37:18Z,patriknw,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorSystem.scala,,,,,1,"@@ -324,13 +324,13 @@ abstract class ExtendedActorSystem extends ActorSystem { + def deathWatch: DeathWatch + + /** +- * ClassLoader which is used for reflective accesses internally. This is set +- * to the context class loader, if one is set, or the class loader which ++ * ClassLoader wrapper which is used for reflective accesses internally. This is set ++ * to use the context class loader, if one is set, or the class loader which + * loaded the ActorSystem implementation. The context class loader is also + * set on all threads created by the ActorSystem, if one was set during + * creation. + */ +- def internalClassLoader: ClassLoader ++ def propertyMaster: PropertyMaster","I understand that, but what about DynamicAccess or DynamicClassMaster. Looking at the signatures it is all about fqcn strings. + +PropertyMaster can be a manager that handles just about anything. +",4b71872aef418639e1033bd7f98edb0e5ea138f4 +443663,0,"Calling `unstashAll()` now throws a `MessageQueueAppendFailedException` in case of a capacity violation (this is also properly documented now). Moreover, the stash size limit is now configurable using `stash-capacity` (an int in the dispatcher section of """,2012-02-13 02:25:43,phaller,akka,akka,,https://github.com/akka/akka-core/pull/307#discussion_r443663,2012-02-13T13:25:43Z,2012-02-28T09:22:30Z,phaller,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/Stash.scala,,,,,1,"@@ -0,0 +1,97 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++package akka.actor ++ ++import akka.dispatch.{ Envelope, DequeBasedMessageQueue } ++ ++/** ++ * The `Stash` trait enables an actor to temporarily stash away messages that can not or ++ * should not be handled using the actor's current behavior. ++ *

++ * Example: ++ *

++ *    class ActorWithProtocol extends Actor with Stash {
++ *      def receive = {
++ *        case ""open"" ⇒
++ *          unstashAll {
++ *            case ""write"" ⇒ // do writing...
++ *            case ""close"" ⇒
++ *              unstashAll()
++ *              context.unbecome()
++ *            case msg ⇒ stash()
++ *          }
++ *        case ""done"" ⇒ // done
++ *        case msg    ⇒ stash()
++ *      }
++ *    }
++ *  
++ * ++ * Note that the `Stash` trait can only be used together with actors that have a deque-based ++ * mailbox. Actors can be configured to use a deque-based mailbox using a configuration like ++ * the following: ++ *
++ *  akka {
++ *    actor {
++ *      default-dispatcher {
++ *        mailboxType = ""akka.dispatch.UnboundedDequeBasedMailbox""
++ *      }
++ *    }
++ *  }
++ *  
++ */ ++trait Stash { ++ thisActor: Actor ⇒ ++ ++ /* The private stash of the actor. It is only accessible using `stash()` and ++ * `unstashAll()`. ++ */ ++ private[this] var theStash = Vector.empty[Envelope] ++ ++ /* The actor's deque-based message queue. ++ * `mailbox.queue` is the underlying `Deque`. ++ */ ++ private[this] val mailbox: DequeBasedMessageQueue = { ++ context.asInstanceOf[ActorCell].mailbox match { ++ case queue: DequeBasedMessageQueue ⇒ queue ++ case other ⇒ throw new ActorInitializationException(self, ""UnboundedDequeBasedMailbox required, got: "" + other.getClass()) ++ } ++ } ++ ++ /** ++ * Adds the current message (the message that the actor received last) to the ++ * actor's stash. ++ */ ++ def stash(): Unit = theStash :+= context.asInstanceOf[ActorCell].currentMessage ++ ++ /** ++ * Prepends all messages in the stash to the mailbox, and then clears the stash. ++ */ ++ def unstashAll(): Unit = { ++ theStash.reverseIterator foreach mailbox.queue.addFirst","Calling `unstashAll()` now throws a `MessageQueueAppendFailedException` in case of a capacity violation (this is also properly documented now). Moreover, the stash size limit is now configurable using `stash-capacity` (an int in the dispatcher section of the config). +",8ea949857b39388ac25bdc08df7feee3757f3ee9 +417230,2,"Damn. Missing the else. Thanks Patrik. Sloppy of me to let this one slip through. I'll fix ASAP. """,2012-02-04 21:03:22,jboner,akka,akka,,https://github.com/akka/akka-core/pull/297#discussion_r417230,2012-02-05T08:03:22Z,2012-02-05T08:20:17Z,jboner,CONTRIBUTOR,akka-actor/src/main/scala/akka/AkkaException.scala,,,,,1,"@@ -7,6 +7,26 @@ package akka + import akka.actor.newUuid + import java.net.{ InetAddress, UnknownHostException } + ++object AkkaException { ++ val hostname = try InetAddress.getLocalHost.getHostAddress catch { case e: UnknownHostException ⇒ ""unknown host"" } ++ ++ def toStringWithStackTrace(throwable: Throwable): String = { ++ if (throwable eq null) ""Unknown Throwable: was 'null'"" ++ throwable match { ++ case ae: AkkaException ⇒ ae.toLongString ++ case e ⇒ ""%s:%s\n%s"" format (e.getClass.getName, e.getMessage, stackTraceToString(e))","Damn. Missing the else. Thanks Patrik. Sloppy of me to let this one slip through. I'll fix ASAP. +",42f5af7fb011059d8098532493eb13ec3116c7e5 +342851,1,"Nice! Please comment that this prevents props and context to be closed over below.""",2012-01-10 23:35:04,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/208#discussion_r342851,2012-01-11T10:35:04Z,2012-01-11T10:42:36Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/routing/Routing.scala,,176.0,,,1,"@@ -171,15 +171,15 @@ trait RouterConfig { + * @see akka.routing.RouterConfig + */ + abstract class CustomRouterConfig extends RouterConfig { +- override def createRoute(props: Props, context: ActorContext, ref: RoutedActorRef): Route = { +- val customRoute = createCustomRoute(props, context, ref) ++ override def createRoute(props: Props, context: ActorContext): Route = { ++ val customRoute = createCustomRoute(props, context)","Nice! Please comment that this prevents props and context to be closed over below. +",bc7b5c92a074da6c4d3f66ce71774e144e531fe8 +342686,0,"So you cannot share the same RouterConfig between multiple Actors?""",2012-01-10 22:11:48,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/206#discussion_r342686,2012-01-11T09:11:48Z,2012-01-11T10:16:56Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/routing/Routing.scala,,,,,1,"@@ -94,18 +116,48 @@ trait RouterConfig { + + protected def toAll(sender: ActorRef, routees: Iterable[ActorRef]): Iterable[Destination] = routees.map(Destination(sender, _)) + +- protected def createRoutees(props: Props, context: ActorContext, nrOfInstances: Int, routees: Iterable[String]): IndexedSeq[ActorRef] = (nrOfInstances, routees) match { ++ def createRoutees(props: Props, context: ActorContext, nrOfInstances: Int, routees: Iterable[String]): IndexedSeq[ActorRef] = (nrOfInstances, routees) match { + case (0, Nil) ⇒ throw new IllegalArgumentException(""Insufficient information - missing configuration."") + case (x, Nil) ⇒ (1 to x).map(_ ⇒ context.actorOf(props))(scala.collection.breakOut) + case (_, xs) ⇒ xs.map(context.actorFor(_))(scala.collection.breakOut) + } + + protected def createAndRegisterRoutees(props: Props, context: ActorContext, nrOfInstances: Int, routees: Iterable[String]): Unit = { +- registerRoutees(context, createRoutees(props, context, nrOfInstances, routees)) ++ resizer match { ++ case None ⇒ registerRoutees(context, createRoutees(props, context, nrOfInstances, routees)) ++ case Some(p) ⇒ resize(props, context, context.self.asInstanceOf[RoutedActorRef].routees) ++ } + } + +- protected def registerRoutees(context: ActorContext, routees: IndexedSeq[ActorRef]): Unit = { +- context.self.asInstanceOf[RoutedActorRef]._routees = routees ++ /** ++ * Adds new routees to the router. ++ */ ++ def registerRoutees(context: ActorContext, routees: IndexedSeq[ActorRef]): Unit = { ++ context.self.asInstanceOf[RoutedActorRef].addRoutees(routees) ++ } ++ ++ /** ++ * Removes routees from the router. This method doesn't stop the routees. ++ */ ++ def unregisterRoutees(context: ActorContext, routees: IndexedSeq[ActorRef]): Unit = { ++ context.self.asInstanceOf[RoutedActorRef].removeRoutees(routees) ++ } ++ ++ def resizer: Option[Resizer] = None ++ ++ private val resizeProgress = new AtomicBoolean ++ private val resizeCounter = new AtomicLong ++ ++ def resize(props: Props, context: ActorContext, currentRoutees: IndexedSeq[ActorRef]) { ++ for (r ← resizer) { ++ if (r.isTimeForResize(resizeCounter.getAndIncrement()) && resizeProgress.compareAndSet(false, true)) {","So you cannot share the same RouterConfig between multiple Actors? +",85b673b63ffd61a02ae1393b8115160e4341a108 +319475,0,"Why does that look so cludgy? can't / just skip nulls and """"""""s?""",2011-12-29 10:54:53,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/196#discussion_r319475,2011-12-29T21:54:53Z,2011-12-29T23:12:59Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala,,,,,1,"@@ -453,22 +453,33 @@ class LocalActorRefProvider( + + def actorFor(ref: InternalActorRef, path: String): InternalActorRef = path match { + case RelativeActorPath(elems) ⇒ +- if (elems.isEmpty) deadLetters +- else if (elems.head.isEmpty) actorFor(rootGuardian, elems.tail) ++ if (elems.isEmpty) { ++ log.debug(""look-up of empty path string '{}' fails (per definition)"", path) ++ deadLetters ++ } else if (elems.head.isEmpty) actorFor(rootGuardian, elems.tail) + else actorFor(ref, elems) + case LocalActorPath(address, elems) if address == rootPath.address ⇒ actorFor(rootGuardian, elems) +- case _ ⇒ deadLetters ++ case _ ⇒ ++ log.debug(""look-up of unknown path '{}' failed"", path) ++ deadLetters + } + + def actorFor(path: ActorPath): InternalActorRef = + if (path.root == rootPath) actorFor(rootGuardian, path.elements) +- else deadLetters ++ else { ++ log.debug(""look-up of foreign ActorPath '{}' failed"", path) ++ deadLetters ++ } + + def actorFor(ref: InternalActorRef, path: Iterable[String]): InternalActorRef = +- if (path.isEmpty) deadLetters +- else ref.getChild(path.iterator) match { +- case Nobody ⇒ deadLetters +- case x ⇒ x ++ if (path.isEmpty) { ++ log.debug(""look-up of empty path sequence fails (per definition)"") ++ deadLetters ++ } else ref.getChild(path.iterator) match { ++ case Nobody ⇒ ++ log.debug(""look-up of path sequence '{}' failed"", path) ++ new EmptyLocalActorRef(eventStream, dispatcher, ref.path / path.filterNot(_.isEmpty))","Why does that look so cludgy? can't / just skip nulls and """"s? +",023f4eb0ecbbcdc6dacb0b73884fc11c3b95f00e +295283,0,"Just tried the actual generated docs. This example comes out a little strange because of the different indenting. I think as two blocks is better for this: .. includecode:: code/TypedActorDocSpec.scala#typed-actor-supercharge .. includecode:: co""",2011-12-14 12:23:14,pvlugter,akka,akka,,https://github.com/akka/akka-core/pull/160#discussion_r295283,2011-12-14T23:23:14Z,2011-12-15T16:19:19Z,pvlugter,MEMBER,akka-docs/scala/typed-actors.rst,,,,,1,"@@ -4,186 +4,160 @@ Typed Actors (Scala) + .. sidebar:: Contents + + .. contents:: :local: +- +-The Typed Actors are implemented through `Typed Actors `_. It uses AOP through `AspectWerkz `_ to turn regular POJOs into asynchronous non-blocking Actors with semantics of the Actor Model. Each method dispatch is turned into a message that is put on a queue to be processed by the Typed Actor sequentially one by one. + +-If you are using the `Spring Framework `_ then take a look at Akka's `Spring integration `_. ++Akka Typed Actors is an implementation of the `Active Objects `_ pattern. ++Essentially turning method invocations into asynchronous dispatch instead of synchronous that has been the default way since Smalltalk came out. + +-**WARNING:** Do not configure to use a ``BalancingDispatcher`` with your ``TypedActors``, it just isn't safe with how ``TypedActors`` currently are implemented. This limitation will most likely be removed in the future. ++Typed Actors consist of 2 ""parts"", a public interface and an implementation, and if you've done any work in ""enterprise"" Java, this will be very familiar to you. As with normal Actors you have an external API (the public interface instance) that will delegate methodcalls asynchronously to ++a private instance of the implementation. + +-Creating Typed Actors +---------------------- +- +-**IMPORTANT:** The Typed Actors class must have access modifier 'public' (which is default) and can't be an inner class (unless it is an inner class in an 'object'). ++The advantage of Typed Actors vs. Actors is that with TypedActors you have a static contract, and don't need to define your own messages, the downside is that it places some limitations on what you can do and what you can't, i.e. you can't use become/unbecome. + +-Akka turns POJOs with interface and implementation into asynchronous (Typed) Actors. Akka is using `AspectWerkz’s Proxy `_ implementation, which is the `most performant `_ proxy implementation there exists. ++Typed Actors are implemented using `JDK Proxies `_ which provide a pretty easy-worked API to intercept method calls. + +-In order to create a Typed Actor you have to subclass the ``TypedActor`` base class. + +-Here is an example. ++The tools of the trade ++---------------------- + +-If you have a POJO with an interface implementation separation like this: ++Before we create our first Typed Actor we should first go through the tools that we have at our disposal, ++it's located in ``akka.actor.TypedActor``. + +-.. code-block:: scala ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: typed-actor-extension-tools + +- import akka.actor.TypedActor ++.. warning:: ++ ++ Same as not exposing ``this`` of an Akka Actor, it's important not to expose ``this`` of a Typed Actor, ++ instead you should pass the external proxy reference, which is obtained from within your Typed Actor as ++ ``TypedActor.self``, this is your external identity, as the ``ActorRef`` is the external identity of ++ and Akka Actor. + +- trait RegistrationService { +- def register(user: User, cred: Credentials): Unit +- def getUserFor(username: String): User +- } +- +-.. code-block:: scala ++Creating Typed Actors ++--------------------- + +- public class RegistrationServiceImpl extends TypedActor with RegistrationService { +- def register(user: User, cred: Credentials) { +- ... // register user +- } ++To create a Typed Actor you need to have one or more interfaces, and one implementation. + +- def getUserFor(username: String): User = { +- ... // fetch user by username +- user +- } +- } ++Our example interface: + +-Then you can create an Typed Actor out of it by creating it through the ``TypedActor`` factory like this: ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: imports,typed-actor-iface ++ :exclude: typed-actor-iface-methods + +-.. code-block:: scala ++Our example implementation of that interface: + +- val service = TypedActor.newInstance(classOf[RegistrationService], classOf[RegistrationServiceImpl], 1000) +- // The last parameter defines the timeout for Future calls ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: imports,typed-actor-impl ++ :exclude: typed-actor-impl-methods + +-Creating Typed Actors with non-default constructor +-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++The most trivial way of creating a Typed Actor instance ++of our Squarer: + +-To create a typed actor that takes constructor arguments use a variant of ``newInstance`` or ``newRemoteInstance`` that takes a call-by-name block in which you can create the Typed Actor in any way you like. ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: typed-actor-create1 + +-Here is an example: ++First type is the type of the proxy, the second type is the type of the implementation. ++If you need to call a specific constructor you do it like this: + +-.. code-block:: scala ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: typed-actor-create2 + +- val service = TypedActor.newInstance(classOf[Service], new ServiceWithConstructorArgs(""someString"", 500L)) ++Since you supply a Props, you can specify which dispatcher to use, what the default timeout should be used and more. ++Now, our Squarer doesn't have any methods, so we'd better add those. + +-Configuration factory class +-^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: imports,typed-actor-iface + +-Using a configuration object: ++Alright, now we've got some methods we can call, but we need to implement those in SquarerImpl. + +-.. code-block:: scala ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: imports,typed-actor-impl + +- import akka.actor.TypedActorConfiguration +- import akka.util.Duration +- import akka.util.duration._ ++Alright, now we have an interface and an implementation of that interface, ++and we know how to create a Typed Actor from that, so let's look at calling these methods. + +- val config = TypedActorConfiguration() +- .timeout(3000 millis) ++Method dispatch semantics ++------------------------- + +- val service = TypedActor.newInstance(classOf[RegistrationService], classOf[RegistrationServiceImpl], config) ++Methods returning: + +-However, often you will not use these factory methods but declaratively define the Typed Actors as part of a supervisor hierarchy. More on that in the :ref:`fault-tolerance-scala` section. ++ * ``Unit`` will be dispatched with ``fire-and-forget`` semantics, exactly like ``Actor.tell`` ++ * ``akka.dispatch.Future[_]`` will use ``send-request-reply`` semantics, exactly like ``Actor.ask`` ++ * ``scala.Option[_]`` or akka.japi.Option[_] will use ``send-request-reply`` semantics, but _will_ block to wait for an answer, ++ and return None if no answer was produced within the timout, or scala.Some/akka.japi.Some containing the result otherwise. ++ Any exception that was thrown during this call will be rethrown. ++ * Any other type of value will use ``send-request-reply`` semantics, but _will_ block to wait for an answer, ++ throwing ``java.util.concurrent.TimeoutException`` if there was a timeout or rethrow any exception that was thrown during this call. + +-Sending messages +----------------- ++Messages and immutability ++------------------------- + +-Messages are sent simply by invoking methods on the POJO, which is proxy to the ""real"" POJO now. The arguments to the method are bundled up atomically into an message and sent to the receiver (the actual POJO instance). ++While Akka cannot enforce that the parameters to the methods of your Typed Actors are immutable, ++we *strongly* recommend that parameters passed are immutable. + + One-way message send + ^^^^^^^^^^^^^^^^^^^^ + +-Methods that return void are turned into ‘fire-and-forget’ semantics by asynchronously firing off the message and return immediately. In the example above it would be the 'register' method, so if this method is invoked then it returns immediately: ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: typed-actor-call-oneway + +-.. code-block:: java +- +- // method invocation returns immediately and method is invoke asynchronously using the Actor Model semantics +- service.register(user, creds) ++As simple as that! The method will be executed on another thread; asynchronously. + + Request-reply message send + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +-Methods that return something (e.g. non-void methods) are turned into ‘send-and-receive-eventually’ semantics by asynchronously firing off the message and wait on the reply using a Future. +- +-.. code-block:: scala ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: typed-actor-call-option + +- // method invocation is asynchronously dispatched using the Actor Model semantics, +- // but it blocks waiting on a Future to be resolved in the background +- val user = service.getUser(username) ++This will block for as long as the timeout that was set in the Props of the Typed Actor, ++if needed. It will return ``None`` if a timeout occurs. + +-Generally it is preferred to use fire-forget messages as much as possible since they will never block, e.g. consume a resource by waiting. But sometimes they are neat to use since they: ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: typed-actor-call-strict + +-* Simulates standard Java method dispatch, which is more intuitive for most Java developers +-* Are a neat to model request-reply +-* Are useful when you need to do things in a defined order ++This will block for as long as the timeout that was set in the Props of the Typed Actor, ++if needed. It will throw a ``java.util.concurrent.TimeoutException`` if a timeout occurs. + + Request-reply-with-future message send + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +-Methods that return a ``akka.dispatch.Future`` are turned into ‘send-and-receive-with-future’ semantics by asynchronously firing off the message and returns immediately with a Future. You need to use the ``future(...)`` method in the ``TypedActor`` base class to resolve the Future that the client code is waiting on. +- +-Here is an example: ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: typed-actor-call-future + +-.. code-block:: scala +- +- class MathTypedActorImpl extends TypedActor with MathTypedActor { +- def square(x: Int): Future[Integer] = future(x * x) +- } +- +- // create the ping actor +- val math = TypedActor.newInstance(classOf[MathTyped], classOf[MathTypedImpl]) +- +- // This method will return immediately when called, caller should wait on the Future for the result +- val future = math.square(10) +- future.await +- val result: Int = future.get ++This call is asynchronous, and the Future returned can be used for asynchronous composition. + + Stopping Typed Actors + --------------------- + +-Once Typed Actors have been created with one of the ``TypedActor.newInstance`` methods they need to be stopped with ``TypedActor.stop`` to free resources allocated by the created Typed Actor (this is not needed when the Typed Actor is supervised). +- +-.. code-block:: scala +- +- // Create Typed Actor +- val service = TypedActor.newInstance(classOf[RegistrationService], classOf[RegistrationServiceImpl], 1000) +- +- // ... ++Since Akkas Typed Actors are backed by Akka Actors they must be stopped when they aren't needed anymore. + +- // Free Typed Actor resources +- TypedActor.stop(service) ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: typed-actor-stop + +-When the Typed Actor defines a shutdown callback method (:ref:`fault-tolerance-scala`) it will be invoked on ``TypedActor.stop``. ++This asynchronously stops the Typed Actor associated with the specified proxy ASAP. + +-How to use the TypedActorContext for runtime information access +---------------------------------------------------------------- ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: typed-actor-poisonpill + +-The ``akka.actor.TypedActorContext`` class Holds 'runtime type information' (RTTI) for the Typed Actor. This context is a member field in the ``TypedActor`` base class and holds for example the current sender reference, the current sender future etc. ++This asynchronously stops the Typed Actor associated with the specified proxy ++after it's done with all calls that were made prior to this call. + +-Here is an example how you can use it to in a 'void' (e.g. fire-forget) method to implement request-reply by using the sender reference: ++Typed Actor Hierarchies ++----------------------- + +-.. code-block:: scala ++Since you can obtain a contextual Typed Actor Extension by passing in an ``ActorContext`` ++you can create child Typed Actors by invoking ``typedActorOf(..)`` on that. + +- class PingImpl extends TypedActor with Ping { +- +- def hit(count: Int) { +- val pong = context.getSender.asInstanceOf[Pong] +- pong.hit(count++) +- } +- } +- +-If the sender, sender future etc. is not available, then these methods will return ``null`` so you should have a way of dealing with that scenario. +- +-Messages and immutability +-------------------------- ++This also works for creating child Typed Actors in regular Akka Actors. + +-**IMPORTANT**: Messages can be any kind of object but have to be immutable (there is a workaround, see next section). Java or Scala can’t enforce immutability (yet) so this has to be by convention. Primitives like String, int, Long are always immutable. Apart from these you have to create your own immutable objects to send as messages. If you pass on a reference to an instance that is mutable then this instance can be modified concurrently by two different Typed Actors and the Actor model is broken leaving you with NO guarantees and most likely corrupt data. ++Lifecycle callbacks ++------------------- + +-Akka can help you in this regard. It allows you to turn on an option for serializing all messages, e.g. all parameters to the Typed Actor effectively making a deep clone/copy of the parameters. This will make sending mutable messages completely safe. This option is turned on in the :ref:`configuration` file like this: ++By having your Typed Actor implementation class implement ``TypedActor.PreStart``, ``TypedActor.PostStop``, ``TypedActor.PreRestart`` and/or ``TypedActor.PostRestart`` you can hook into the lifecyle of your Typed Actor. + +-.. code-block:: ruby ++Supercharging ++------------- + +- akka { +- actor { +- serialize-messages = on # does a deep clone of messages to ensure immutability +- } +- } ++Here's an example on how you can use traits to mix in behavior in your Typed Actors. + +-This will make a deep clone (using Java serialization) of all parameters. ++.. includecode:: code/TypedActorDocSpec.scala ++ :include: typed-actor-supercharge,typed-actor-supercharge-usage","Just tried the actual generated docs. This example comes out a little strange because of the different indenting. I think as two blocks is better for this: + +``` +.. includecode:: code/TypedActorDocSpec.scala#typed-actor-supercharge + +.. includecode:: code/TypedActorDocSpec.scala#typed-actor-supercharge-usage +``` +",9d2ab2e7145ed1e200ed29aee42f9a5734f108ab +258115,2,"I find it a bit weird to have a method called """"toValue"""" that returns a key-value pair...""",2011-11-29 05:56:01,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/129#discussion_r258115,2011-11-29T16:56:01Z,2011-12-02T07:52:49Z,viktorklang,CONTRIBUTOR,akka-actor-tests/src/test/scala/akka/performance/workbench/Report.scala,,,,,1,"@@ -222,7 +222,7 @@ class Report( + sb.append(""Akka version: "").append(system.settings.ConfigVersion) + sb.append(""\n"") + sb.append(""Akka config:"") +- for ((key, value) ← system.settings.config.toObject) { ++ for ((key, value) ← system.settings.config.toValue) {","I find it a bit weird to have a method called ""toValue"" that returns a key-value pair... +",66bf11681c88b7ba58e9a3134374d21065130937 +269614,1,"You guessed it. Also, use pbhash :-)""",2011-12-05 01:21:44,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/119#discussion_r269614,2011-12-05T12:21:44Z,2011-12-05T21:48:28Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorPath.scala,,145.0,,,202,"@@ -85,48 +59,119 @@ trait ActorPath { + def /(child: Iterable[String]): ActorPath = (this /: child)(_ / _) + + /** +- * String representation of this path. Different from toString for root path. ++ * Sequence of names for this path. Performance implication: has to allocate a list. + */ +- def string: String ++ def pathElements: Iterable[String] + + /** +- * Sequence of names for this path. ++ * Walk up the tree to obtain and return the RootActorPath. + */ +- def path: Iterable[String] ++ def root: RootActorPath + +- /** +- * Is this the root path? +- */ +- def isRoot: Boolean + } + +-class RootActorPath(val remoteAddress: RemoteAddress) extends ActorPath { +- +- def name: String = ""/"" ++/** ++ * Root of the hierarchy of ActorPaths. There is exactly root per ActorSystem ++ * and node (for remote-enabled or clustered systems). ++ */ ++final case class RootActorPath(address: Address, name: String = ActorPath.separator) extends ActorPath { + + def parent: ActorPath = this + +- def /(child: String): ActorPath = new ChildActorPath(remoteAddress, this, child) ++ def root: RootActorPath = this + +- def string: String = """" ++ def /(child: String): ActorPath = new ChildActorPath(this, child) + +- def path: Iterable[String] = Iterable.empty ++ val pathElements: Iterable[String] = List("""") + +- def isRoot: Boolean = true ++ override val toString = address + name + +- override def toString = ActorPath.separator ++ def compareTo(other: ActorPath) = other match { ++ case r: RootActorPath ⇒ toString compareTo r.toString ++ case c: ChildActorPath ⇒ 1 ++ } + } + +-class ChildActorPath(val remoteAddress: RemoteAddress, val parent: ActorPath, val name: String) extends ActorPath { ++final class ChildActorPath(val parent: ActorPath, val name: String) extends ActorPath { + +- def /(child: String): ActorPath = new ChildActorPath(remoteAddress, this, child) ++ def address: Address = root.address + +- def string: String = parent.string + ActorPath.separator + name ++ def /(child: String): ActorPath = new ChildActorPath(this, child) + +- def path: Iterable[String] = parent.path ++ Iterable(name) ++ def pathElements: Iterable[String] = { ++ @tailrec ++ def rec(p: ActorPath, acc: List[String]): Iterable[String] = p match { ++ case r: RootActorPath ⇒ acc ++ case _ ⇒ rec(p.parent, p.name :: acc) ++ } ++ rec(this, Nil) ++ } + +- def isRoot: Boolean = false ++ def root = { ++ @tailrec ++ def rec(p: ActorPath): RootActorPath = p match { ++ case r: RootActorPath ⇒ r ++ case _ ⇒ rec(p.parent) ++ } ++ rec(this) ++ } + +- override def toString = string ++ // TODO research whether this should be cached somehow (might be fast enough, but creates GC pressure) ++ /* ++ * idea: add one field which holds the total length (because that is known) ++ * so that only one String needs to be allocated before traversal; this is ++ * cheaper than any cache ++ */ ++ override def toString = { ++ @tailrec ++ def rec(p: ActorPath, s: String): String = p match { ++ case r: RootActorPath ⇒ r + s ++ case _ if s.isEmpty ⇒ rec(p.parent, name) ++ case _ ⇒ rec(p.parent, p.name + ActorPath.separator + s) ++ } ++ rec(this, """") ++ } ++ ++ override def equals(other: Any): Boolean = { ++ @tailrec ++ def rec(left: ActorPath, right: ActorPath): Boolean = ++ if (left eq right) true ++ else if (left.isInstanceOf[RootActorPath]) left equals right ++ else if (right.isInstanceOf[RootActorPath]) right equals left ++ else left.name == right.name && rec(left.parent, right.parent) ++ ++ other match { ++ case p: ActorPath ⇒ rec(this, p) ++ case _ ⇒ false ++ } ++ } ++ ++ // TODO RK investigate Phil’s hash from scala.collection.mutable.HashTable.improve ++ override def hashCode: Int = {","You guessed it. + +Also, use pbhash :-) +",9d7597c7282711889d74bd9b4d7bdae5ea254104 +221048,0,"Drop all constructors except for this one""",2011-11-10 01:47:25,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/106#discussion_r221048,2011-11-10T12:47:25Z,2011-11-10T15:33:03Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/java/org/jboss/netty/akka/util/HashedWheelTimer.java,,103.0,,,103,"@@ -0,0 +1,555 @@ ++/* ++ * Copyright 2009 Red Hat, Inc. ++ * ++ * Red Hat licenses this file to you under the Apache License, version 2.0 ++ * (the ""License""); you may not use this file except in compliance with the ++ * License. You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an ""AS IS"" BASIS, WITHOUT ++ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the ++ * License for the specific language governing permissions and limitations ++ * under the License. ++ */ ++package org.jboss.netty.akka.util; ++ ++import java.util.ArrayList; ++import java.util.Collections; ++import java.util.HashSet; ++import java.util.List; ++import java.util.Set; ++import java.util.concurrent.Executors; ++import java.util.concurrent.ThreadFactory; ++import java.util.concurrent.TimeUnit; ++import java.util.concurrent.atomic.AtomicBoolean; ++import java.util.concurrent.atomic.AtomicInteger; ++import java.util.concurrent.locks.ReadWriteLock; ++import java.util.concurrent.locks.ReentrantReadWriteLock; ++ ++import org.jboss.netty.akka.logging.InternalLogger; ++import org.jboss.netty.akka.logging.InternalLoggerFactory; ++import org.jboss.netty.akka.util.internal.ConcurrentIdentityHashMap; ++import org.jboss.netty.akka.util.internal.ReusableIterator; ++import org.jboss.netty.akka.util.internal.SharedResourceMisuseDetector; ++ ++/** ++ * A {@link Timer} optimized for approximated I/O timeout scheduling. ++ * ++ *

Tick Duration

++ * ++ * As described with 'approximated', this timer does not execute the scheduled ++ * {@link TimerTask} on time. {@link org.jboss.netty.akka.util.HashedWheelTimer}, on every tick, will ++ * check if there are any {@link TimerTask}s behind the schedule and execute ++ * them. ++ *

++ * You can increase or decrease the accuracy of the execution timing by ++ * specifying smaller or larger tick duration in the constructor. In most ++ * network applications, I/O timeout does not need to be accurate. Therefore, ++ * the default tick duration is 100 milliseconds and you will not need to try ++ * different configurations in most cases. ++ * ++ *

Ticks per Wheel (Wheel Size)

++ * ++ * {@link org.jboss.netty.akka.util.HashedWheelTimer} maintains a data structure called 'wheel'. ++ * To put simply, a wheel is a hash table of {@link TimerTask}s whose hash ++ * function is 'dead line of the task'. The default number of ticks per wheel ++ * (i.e. the size of the wheel) is 512. You could specify a larger value ++ * if you are going to schedule a lot of timeouts. ++ * ++ *

Do not create many instances.

++ * ++ * {@link org.jboss.netty.akka.util.HashedWheelTimer} creates a new thread whenever it is instantiated and ++ * started. Therefore, you should make sure to create only one instance and ++ * share it across your application. One of the common mistakes, that makes ++ * your application unresponsive, is to create a new instance in ++ * {@link ChannelPipelineFactory}, which results in the creation of a new thread ++ * for every connection. ++ * ++ *

Implementation Details

++ * ++ * {@link org.jboss.netty.akka.util.HashedWheelTimer} is based on ++ * George Varghese and ++ * Tony Lauck's paper, ++ * 'Hashed ++ * and Hierarchical Timing Wheels: data structures to efficiently implement a ++ * timer facility'. More comprehensive slides are located ++ * here. ++ * ++ * @author The Netty Project ++ * @author Trustin Lee ++ * @version $Rev: 2297 $, $Date: 2010-06-07 10:50:02 +0900 (Mon, 07 Jun 2010) $ ++ */ ++public class HashedWheelTimer implements Timer { ++ ++ static final InternalLogger logger = ++ InternalLoggerFactory.getInstance(HashedWheelTimer.class); ++ private static final AtomicInteger id = new AtomicInteger(); ++ ++ private static final SharedResourceMisuseDetector misuseDetector = ++ new SharedResourceMisuseDetector(HashedWheelTimer.class); ++ ++ private final Worker worker = new Worker(); ++ final Thread workerThread; ++ final AtomicBoolean shutdown = new AtomicBoolean(); ++ ++ private final long roundDuration; ++ final long tickDuration; ++ final Set[] wheel; ++ final ReusableIterator[] iterators; ++ final int mask; ++ final ReadWriteLock lock = new ReentrantReadWriteLock(); ++ volatile int wheelCursor; ++ ++ /** ++ * Creates a new timer with the default thread factory ++ * ({@link java.util.concurrent.Executors#defaultThreadFactory()}), default tick duration, and ++ * default number of ticks per wheel. ++ */ ++ public HashedWheelTimer() { ++ this(Executors.defaultThreadFactory()); ++ } ++ ++ /** ++ * Creates a new timer with the default thread factory ++ * ({@link java.util.concurrent.Executors#defaultThreadFactory()}) and default number of ticks ++ * per wheel. ++ * ++ * @param tickDuration the duration between tick ++ * @param unit the time unit of the {@code tickDuration} ++ */ ++ public HashedWheelTimer(long tickDuration, TimeUnit unit) { ++ this(Executors.defaultThreadFactory(), tickDuration, unit); ++ } ++ ++ /** ++ * Creates a new timer with the default thread factory ++ * ({@link java.util.concurrent.Executors#defaultThreadFactory()}). ++ * ++ * @param tickDuration the duration between tick ++ * @param unit the time unit of the {@code tickDuration} ++ * @param ticksPerWheel the size of the wheel ++ */ ++ public HashedWheelTimer(long tickDuration, TimeUnit unit, int ticksPerWheel) { ++ this(Executors.defaultThreadFactory(), tickDuration, unit, ticksPerWheel); ++ } ++ ++ /** ++ * Creates a new timer with the default tick duration and default number of ++ * ticks per wheel. ++ * ++ * @param threadFactory a {@link java.util.concurrent.ThreadFactory} that creates a ++ * background {@link Thread} which is dedicated to ++ * {@link TimerTask} execution. ++ */ ++ public HashedWheelTimer(ThreadFactory threadFactory) { ++ this(threadFactory, 100, TimeUnit.MILLISECONDS); ++ } ++ ++ /** ++ * Creates a new timer with the default number of ticks per wheel. ++ * ++ * @param threadFactory a {@link java.util.concurrent.ThreadFactory} that creates a ++ * background {@link Thread} which is dedicated to ++ * {@link TimerTask} execution. ++ * @param tickDuration the duration between tick ++ * @param unit the time unit of the {@code tickDuration} ++ */ ++ public HashedWheelTimer( ++ ThreadFactory threadFactory, long tickDuration, TimeUnit unit) { ++ this(threadFactory, tickDuration, unit, 512); ++ } ++ ++ /** ++ * Creates a new timer. ++ * ++ * @param threadFactory a {@link java.util.concurrent.ThreadFactory} that creates a ++ * background {@link Thread} which is dedicated to ++ * {@link TimerTask} execution. ++ * @param tickDuration the duration between tick ++ * @param unit the time unit of the {@code tickDuration} ++ * @param ticksPerWheel the size of the wheel ++ */ ++ public HashedWheelTimer(","Drop all constructors except for this one +",1577f8bcb32097e2e317302089d92fd417b69913 +20216,0,"Why does it require a HashSet?""",2011-04-17 23:39:45,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/73#discussion_r20216,2011-04-18T11:39:45Z,2011-04-18T11:39:45Z,viktorklang,CONTRIBUTOR,akka-stm/src/main/scala/stm/TransactionalSet.scala,,32.0,,,32,"@@ -0,0 +1,88 @@ ++package akka.stm ++ ++/** ++ * TransactionalSet : completely based on TransactionalMap ++ * @author - Dhananjay Nene ++ */ ++ ++/* ++ * TODO: Change package names in imports. This has been compiled against akka_2.8.0-1.0-M1.zip ++ */ ++ ++import scala.collection.mutable.HashSet ++import se.scalablesolutions.akka.stm.{Transactional, Ref} ++import se.scalablesolutions.akka.actor.{newUuid} ++ ++/** ++ * Transactional set that implements the mutable Set interface with an underlying Ref and HashSet. ++ */ ++ ++object TransactionalSet { ++ def apply[K]() = new TransactionalSet[K]() ++ ++ def apply[K](elems: K*) = new TransactionalSet(HashSet(elems: _*)) ++} ++ ++/** ++ * Transactional Set that implements the mutable Set interface with an underlying Ref and HashSet. ++ * ++ * From Scala you can use TSet as a shorter alias for TransactionalSet. ++ */ ++ ++class TransactionalSet[T](initialValue: HashSet[T]) extends Transactional with scala.collection.mutable.Set[T] {","Why does it require a HashSet? +",95aff5ef78f4b8aca6f624f1402f3198acab056b +507277,0,"done""",2012-03-01 05:13:09,RayRoestenburg,akka,akka,,https://github.com/akka/akka-core/pull/344#discussion_r507277,2012-03-01T16:13:09Z,2012-03-20T12:17:27Z,RayRoestenburg,CONTRIBUTOR,akka-camel/src/main/scala/akka/camel/internal/ActivationTracker.scala,,,,,1,"@@ -0,0 +1,88 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++ ++package akka.camel.internal ++ ++import akka.actor._ ++import collection.mutable.WeakHashMap ++ ++class ActivationTracker extends Actor with ActorLogging { ++ val activations = new WeakHashMap[ActorRef, ActivationStateMachine] ++ ++ class ActivationStateMachine { ++ type State = PartialFunction[ActivationMessage, Unit] ++ ++ var receive: State = notActivated() ++ ++ def notActivated(): State = { ++ var awaitingActivation = List[ActorRef]() ++ var awaitingDeActivation = List[ActorRef]() ++ ++ { ++ case AwaitActivation(ref) ⇒ awaitingActivation ::= sender ++ case AwaitDeActivation(ref) ⇒ awaitingDeActivation ::= sender ++ ++ case msg @ EndpointActivated(ref) ⇒ { ++ awaitingActivation.foreach(_ ! msg) ++ receive = activated(awaitingDeActivation) ++ } ++ ++ case EndpointFailedToActivate(ref, cause) ⇒ { ++ awaitingActivation.foreach(_ ! EndpointFailedToActivate(ref, cause)) ++ receive = failedToActivate(cause) ++ } ++ } ++ } ++ ++ def activated(currentAwaitingDeActivation: List[ActorRef]): State = { ++ var awaitingDeActivation = currentAwaitingDeActivation ++ ++ { ++ case AwaitActivation(ref) ⇒ sender ! EndpointActivated(ref) ++ case AwaitDeActivation(ref) ⇒ awaitingDeActivation ::= sender ++ case msg @ EndpointDeActivated(ref) ⇒ { ++ awaitingDeActivation foreach (_ ! msg) ++ receive = deactivated ++ } ++ case msg @ EndpointFailedToDeActivate(ref, cause) ⇒ {","done +",f74616f828d3e31724d768dd86ce05af85d97ade +506518,2,"Holy shit, github has completely fucked my review :(""",2012-03-01 01:47:50,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/329#discussion_r506518,2012-03-01T12:47:50Z,2012-03-12T18:22:15Z,viktorklang,CONTRIBUTOR,akka-cluster/src/main/scala/akka/cluster/Node.scala,,239.0,,,239,"@@ -0,0 +1,803 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++ ++package akka.cluster ++ ++import akka.actor._ ++import akka.actor.Status._ ++import akka.remote._ ++import akka.routing._ ++import akka.event.Logging ++import akka.dispatch.Await ++import akka.pattern.ask ++import akka.util._ ++import akka.config.ConfigurationException ++ ++import java.util.concurrent.atomic.{ AtomicReference, AtomicBoolean } ++import java.util.concurrent.TimeUnit._ ++import java.util.concurrent.TimeoutException ++import java.security.SecureRandom ++ ++import scala.collection.immutable.{ Map, SortedSet } ++import scala.annotation.tailrec ++ ++import com.google.protobuf.ByteString ++ ++/** ++ * Interface for membership change listener. ++ */ ++trait MembershipChangeListener { ++ def notify(members: SortedSet[Member]): Unit ++} ++ ++/** ++ * Interface for meta data change listener. ++ */ ++trait MetaDataChangeListener { // FIXME add management and notification for MetaDataChangeListener ++ def notify(meta: Map[String, Array[Byte]]): Unit ++} ++ ++// FIXME create Protobuf messages out of all the Gossip stuff - but wait until the prototol is fully stablized. ++ ++/** ++ * Base trait for all cluster messages. All ClusterMessage's are serializable. ++ */ ++sealed trait ClusterMessage extends Serializable ++ ++/** ++ * Cluster commands sent by the USER. ++ */ ++object ClusterAction { ++ ++ /** ++ * Command to join the cluster. Sent when a node (reprsesented by 'address') ++ * wants to join another node (the receiver). ++ */ ++ case class Join(address: Address) extends ClusterMessage ++ ++ /** ++ * Command to set a node to Up (from Joining). ++ */ ++ case object Up extends ClusterMessage ++ ++ /** ++ * Command to leave the cluster. ++ */ ++ case object Leave extends ClusterMessage ++ ++ /** ++ * Command to mark node as temporary down. ++ */ ++ case object Down extends ClusterMessage ++ ++ /** ++ * Command to mark a node to be removed from the cluster immediately. ++ */ ++ case object Exit extends ClusterMessage ++ ++ /** ++ * Command to remove a node from the cluster immediately. ++ */ ++ case object Remove extends ClusterMessage ++} ++ ++/** ++ * Represents the address and the current status of a cluster member node. ++ */ ++case class Member(address: Address, status: MemberStatus) extends ClusterMessage ++ ++/** ++ * Envelope adding a sender address to the gossip. ++ */ ++case class GossipEnvelope(sender: Member, gossip: Gossip) extends ClusterMessage ++ ++/** ++ * Defines the current status of a cluster member node ++ * ++ * Can be one of: Joining, Up, Leaving, Exiting and Down. ++ */ ++sealed trait MemberStatus extends ClusterMessage ++object MemberStatus { ++ case object Joining extends MemberStatus ++ case object Up extends MemberStatus ++ case object Leaving extends MemberStatus ++ case object Exiting extends MemberStatus ++ case object Down extends MemberStatus ++ case object Removed extends MemberStatus ++} ++ ++// sealed trait PartitioningStatus ++// object PartitioningStatus { ++// case object Complete extends PartitioningStatus ++// case object Awaiting extends PartitioningStatus ++// } ++ ++// case class PartitioningChange( ++// from: Address, ++// to: Address, ++// path: PartitionPath, ++// status: PartitioningStatus) ++ ++/** ++ * Represents the overview of the cluster, holds the cluster convergence table and set with unreachable nodes. ++ */ ++case class GossipOverview( ++ seen: Map[Address, VectorClock] = Map.empty[Address, VectorClock], ++ unreachable: Set[Address] = Set.empty[Address]) { ++ ++ override def toString = ++ ""GossipOverview(seen = ["" + seen.mkString("", "") + ++ ""], unreachable = ["" + unreachable.mkString("", "") + ++ ""])"" ++} ++ ++/** ++ * Represents the state of the cluster; cluster ring membership, ring convergence, meta data - all versioned by a vector clock. ++ */ ++case class Gossip( ++ overview: GossipOverview = GossipOverview(), ++ members: SortedSet[Member], // sorted set of members with their status, sorted by name ++ //partitions: Tree[PartitionPath, Node] = Tree.empty[PartitionPath, Node], // name/partition service ++ //pending: Set[PartitioningChange] = Set.empty[PartitioningChange], ++ meta: Map[String, Array[Byte]] = Map.empty[String, Array[Byte]], ++ version: VectorClock = VectorClock()) // vector clock version ++ extends ClusterMessage // is a serializable cluster message ++ with Versioned[Gossip] { ++ ++ /** ++ * Increments the version for this 'Node'. ++ */ ++ def +(node: VectorClock.Node): Gossip = copy(version = version + node) ++ ++ def +(member: Member): Gossip = { ++ if (members contains member) this ++ else this copy (members = members + member) ++ } ++ ++ /** ++ * Marks the gossip as seen by this node (remoteAddress) by updating the address entry in the 'gossip.overview.seen' ++ * Map with the VectorClock for the new gossip. ++ */ ++ def seen(address: Address): Gossip = ++ this copy (overview = overview copy (seen = overview.seen + (address -> version))) ++ ++ override def toString = ++ ""Gossip("" + ++ ""overview = "" + overview + ++ "", members = ["" + members.mkString("", "") + ++ ""], meta = ["" + meta.mkString("", "") + ++ ""], version = "" + version +","Holy shit, github has completely fucked my review :( +",cf3fa9fa3ce9e9312db0922370c93ce1af9db7c8 +434846,0,"?""",2012-02-09 09:41:46,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/318#discussion_r434846,2012-02-09T20:41:46Z,2012-02-10T09:40:42Z,viktorklang,CONTRIBUTOR,akka-docs/scala/code/akka/docs/zeromq/ZeromqDocSpec.scala,,,,,1,"@@ -0,0 +1,187 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++package akka.docs.zeromq ++ ++import akka.actor.Actor ++import akka.actor.Props ++import akka.util.duration._ ++import akka.testkit._ ++import akka.zeromq.ZeroMQVersion ++import akka.zeromq.ZeroMQExtension ++import java.text.SimpleDateFormat ++import java.util.Date ++import akka.zeromq.SocketType ++import akka.zeromq.Bind ++ ++object ZeromqDocSpec { ++ ++ //#health ++ import akka.zeromq._ ++ import akka.actor.Actor ++ import akka.actor.Props ++ import akka.actor.ActorLogging ++ import akka.serialization.SerializationExtension ++ import java.lang.management.ManagementFactory ++ ++ case object Tick ++ case class Heap(timestamp: Long, used: Long, max: Long) ++ case class Load(timestamp: Long, loadAverage: Double) ++ ++ class HealthProbe extends Actor { ++ ++ val pubSocket = context.system.newSocket(SocketType.Pub, Bind(""tcp://127.0.0.1:1235"")) ++ val memory = ManagementFactory.getMemoryMXBean ++ val os = ManagementFactory.getOperatingSystemMXBean ++ val ser = SerializationExtension(context.system) ++ ++ context.system.scheduler.schedule(1 second, 1 second, self, Tick) ++ ++ def receive: Receive = { ++ case Tick ⇒ ++ val currentHeap = memory.getHeapMemoryUsage ++ val timestamp = System.currentTimeMillis ++ ++ // use akka SerializationExtension to convert to bytes ++ val heapPayload = ser.serialize(Heap(timestamp, currentHeap.getUsed, currentHeap.getMax)).fold(throw _, identity) ++ // the first frame is the topic, second is the message ++ pubSocket ! ZMQMessage(Seq(Frame(""health.heap""), Frame(heapPayload))) ++ ++ // use akka SerializationExtension to convert to bytes ++ val loadPayload = ser.serialize(Load(timestamp, os.getSystemLoadAverage)).fold(throw _, identity) ++ // the first frame is the topic, second is the message ++ pubSocket ! ZMQMessage(Seq(Frame(""health.load""), Frame(loadPayload))) ++ } ++ } ++ //#health ++ ++ //#logger ++ class Logger extends Actor with ActorLogging { ++ ++ context.system.newSocket(SocketType.Sub, Listener(self), Connect(""tcp://127.0.0.1:1235""), Subscribe(""health"")) ++ val ser = SerializationExtension(context.system) ++ val timestampFormat = new SimpleDateFormat(""HH:mm:ss.SSS"") ++ ++ def receive = { ++ // the first frame is the topic, second is the message ++ case m: ZMQMessage if m.firstFrameAsString == ""health.heap"" ⇒ ++ ser.deserialize(m.payload(1), classOf[Heap], None) match { ++ case Right(Heap(timestamp, used, max)) ⇒ ++ log.info(""Used heap {} bytes, at {}"", used, timestampFormat.format(new Date(timestamp))) ++ case Left(e) ⇒ throw e ++ } ++ ++ case m: ZMQMessage if m.firstFrameAsString == ""health.load"" ⇒ ++ ser.deserialize(m.payload(1), classOf[Load], None) match { ++ case Right(Load(timestamp, loadAverage)) ⇒ ++ log.info(""Load average {}, at {}"", loadAverage, timestampFormat.format(new Date(timestamp))) ++ case Left(e) ⇒ throw e ++ } ++ } ++ } ++ //#logger ++ ++ //#alerter ++ class HeapAlerter extends Actor with ActorLogging { ++ ++ context.system.newSocket(SocketType.Sub, Listener(self), Connect(""tcp://127.0.0.1:1235""), Subscribe(""health.heap"")) ++ val ser = SerializationExtension(context.system) ++ var count = 0 ++ ++ def receive = { ++ // the first frame is the topic, second is the message ++ case m: ZMQMessage if m.firstFrameAsString == ""health.heap"" ⇒ ++ ser.deserialize(m.payload(1), classOf[Heap], None) match { ++ case Right(Heap(timestamp, used, max)) ⇒ ++ if ((used.toDouble / max) > 0.9) count += 1 ++ else count = 0 ++ if (count > 10) log.warning(""Need more memory, using {} %"", (100.0 * used / max)) ++ case Left(e) ⇒ throw e ++ } ++ } ++ } ++ //#alerter ++ ++} ++ ++class ZeromqDocSpec extends AkkaSpec(""akka.loglevel=INFO"") { ++ import ZeromqDocSpec._ ++ ++ ""demonstrate how to create socket"" in { ++ checkZeroMQInstallation() ++ ++ //#pub-socket ++ import akka.zeromq.ZeroMQExtension ++ val pubSocket = ZeroMQExtension(system).newSocket(SocketType.Pub, Bind(""tcp://127.0.0.1:1234"")) ++ //#pub-socket ++ ++ //#pub-socket2 ++ import akka.zeromq._ ++ val pubSocket2 = system.newSocket(SocketType.Pub, Bind(""tcp://127.0.0.1:1234"")) ++ //#pub-socket2 ++ ++ //#sub-socket ++ import akka.zeromq._ ++ val listener = system.actorOf(Props(new Actor { ++ def receive: Receive = { ++ case Connecting ⇒ //... ++ case m: ZMQMessage ⇒ //... ++ case _ ⇒ //... ++ } ++ })) ++ val subSocket = system.newSocket(SocketType.Sub, Listener(listener), Connect(""tcp://127.0.0.1:1234""), SubscribeAll) ++ //#sub-socket ++ ++ //#sub-topic-socket ++ val subTopicSocket = system.newSocket(SocketType.Sub, Listener(listener), Connect(""tcp://127.0.0.1:1234""), Subscribe(""foo.bar"")) ++ //#sub-topic-socket ++ ++ //#unsub-topic-socket ++ subTopicSocket ! Unsubscribe(""foo.bar"") ++ //#unsub-topic-socket ++ ++ val payload = Array.empty[Byte] ++ //#pub-topic ++ pubSocket ! ZMQMessage(Seq(Frame(""foo.bar""), Frame(payload))) ++ //#pub-topic ++ ++ //#high-watermark ++ val highWatermarkSocket = system.newSocket( ++ SocketType.Router, ++ Listener(listener), ++ Bind(""tcp://127.0.0.1:1234""), ++ HighWatermark(50000)) ++ //#high-watermark ++ } ++ ++ ""demonstrate pub-sub"" in { ++ checkZeroMQInstallation() ++ ++ //#health ++ ++ system.actorOf(Props[HealthProbe], name = ""health"") ++ //#health ++ ++ //#logger ++ ++ system.actorOf(Props[Logger], name = ""logger"") ++ //#logger ++ ++ //#alerter ++ ++ system.actorOf(Props[HeapAlerter], name = ""alerter"") ++ //#alerter ++ ++ Thread.sleep(3000)","? +",5b50ca96f2b3e4fc32f077e730e050f99cddfe79 +297217,2,"Trust me, I have spent quite some time pondering these issues. The ask/? we have for 2.0 is the least of all evils.""",2011-12-15 07:00:08,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/147#discussion_r297217,2011-12-15T18:00:08Z,2011-12-15T18:00:08Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorRef.scala,,450.0,,,58,"@@ -455,11 +448,13 @@ class AskActorRef( + } + + override def ?(message: Any)(implicit timeout: Timeout): Future[Any] =","Trust me, I have spent quite some time pondering these issues. +The ask/? we have for 2.0 is the least of all evils. +",0af92f24400f1b05d1919be54dfd822037f0076f +506515,2,"WDYM? Are you ironic? What is wrong? Please provide understandable feedback. """,2012-03-01 01:46:47,jboner,akka,akka,,https://github.com/akka/akka-core/pull/329#discussion_r506515,2012-03-01T12:46:47Z,2012-03-12T18:22:15Z,jboner,CONTRIBUTOR,akka-cluster/src/main/scala/akka/cluster/Node.scala,,,,,1,"@@ -0,0 +1,803 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++ ++package akka.cluster ++ ++import akka.actor._ ++import akka.actor.Status._ ++import akka.remote._ ++import akka.routing._ ++import akka.event.Logging ++import akka.dispatch.Await ++import akka.pattern.ask ++import akka.util._ ++import akka.config.ConfigurationException ++ ++import java.util.concurrent.atomic.{ AtomicReference, AtomicBoolean } ++import java.util.concurrent.TimeUnit._ ++import java.util.concurrent.TimeoutException ++import java.security.SecureRandom ++ ++import scala.collection.immutable.{ Map, SortedSet } ++import scala.annotation.tailrec ++ ++import com.google.protobuf.ByteString ++ ++/** ++ * Interface for membership change listener. ++ */ ++trait MembershipChangeListener { ++ def notify(members: SortedSet[Member]): Unit ++} ++ ++/** ++ * Interface for meta data change listener. ++ */ ++trait MetaDataChangeListener { // FIXME add management and notification for MetaDataChangeListener ++ def notify(meta: Map[String, Array[Byte]]): Unit ++} ++ ++// FIXME create Protobuf messages out of all the Gossip stuff - but wait until the prototol is fully stablized. ++ ++/** ++ * Base trait for all cluster messages. All ClusterMessage's are serializable. ++ */ ++sealed trait ClusterMessage extends Serializable ++ ++/** ++ * Cluster commands sent by the USER. ++ */ ++object ClusterAction { ++ ++ /** ++ * Command to join the cluster. Sent when a node (reprsesented by 'address') ++ * wants to join another node (the receiver). ++ */ ++ case class Join(address: Address) extends ClusterMessage ++ ++ /** ++ * Command to set a node to Up (from Joining). ++ */ ++ case object Up extends ClusterMessage ++ ++ /** ++ * Command to leave the cluster. ++ */ ++ case object Leave extends ClusterMessage ++ ++ /** ++ * Command to mark node as temporary down. ++ */ ++ case object Down extends ClusterMessage ++ ++ /** ++ * Command to mark a node to be removed from the cluster immediately. ++ */ ++ case object Exit extends ClusterMessage ++ ++ /** ++ * Command to remove a node from the cluster immediately. ++ */ ++ case object Remove extends ClusterMessage ++} ++ ++/** ++ * Represents the address and the current status of a cluster member node. ++ */ ++case class Member(address: Address, status: MemberStatus) extends ClusterMessage ++ ++/** ++ * Envelope adding a sender address to the gossip. ++ */ ++case class GossipEnvelope(sender: Member, gossip: Gossip) extends ClusterMessage ++ ++/** ++ * Defines the current status of a cluster member node ++ * ++ * Can be one of: Joining, Up, Leaving, Exiting and Down. ++ */ ++sealed trait MemberStatus extends ClusterMessage ++object MemberStatus { ++ case object Joining extends MemberStatus ++ case object Up extends MemberStatus ++ case object Leaving extends MemberStatus ++ case object Exiting extends MemberStatus ++ case object Down extends MemberStatus ++ case object Removed extends MemberStatus ++} ++ ++// sealed trait PartitioningStatus ++// object PartitioningStatus { ++// case object Complete extends PartitioningStatus ++// case object Awaiting extends PartitioningStatus ++// } ++ ++// case class PartitioningChange( ++// from: Address, ++// to: Address, ++// path: PartitionPath, ++// status: PartitioningStatus) ++ ++/** ++ * Represents the overview of the cluster, holds the cluster convergence table and set with unreachable nodes. ++ */ ++case class GossipOverview( ++ seen: Map[Address, VectorClock] = Map.empty[Address, VectorClock], ++ unreachable: Set[Address] = Set.empty[Address]) { ++ ++ override def toString = ++ ""GossipOverview(seen = ["" + seen.mkString("", "") + ++ ""], unreachable = ["" + unreachable.mkString("", "") + ++ ""])"" ++} ++ ++/** ++ * Represents the state of the cluster; cluster ring membership, ring convergence, meta data - all versioned by a vector clock. ++ */ ++case class Gossip( ++ overview: GossipOverview = GossipOverview(), ++ members: SortedSet[Member], // sorted set of members with their status, sorted by name ++ //partitions: Tree[PartitionPath, Node] = Tree.empty[PartitionPath, Node], // name/partition service ++ //pending: Set[PartitioningChange] = Set.empty[PartitioningChange], ++ meta: Map[String, Array[Byte]] = Map.empty[String, Array[Byte]], ++ version: VectorClock = VectorClock()) // vector clock version ++ extends ClusterMessage // is a serializable cluster message ++ with Versioned[Gossip] { ++ ++ /** ++ * Increments the version for this 'Node'. ++ */ ++ def +(node: VectorClock.Node): Gossip = copy(version = version + node) ++ ++ def +(member: Member): Gossip = { ++ if (members contains member) this ++ else this copy (members = members + member) ++ } ++ ++ /** ++ * Marks the gossip as seen by this node (remoteAddress) by updating the address entry in the 'gossip.overview.seen' ++ * Map with the VectorClock for the new gossip. ++ */ ++ def seen(address: Address): Gossip = ++ this copy (overview = overview copy (seen = overview.seen + (address -> version))) ++ ++ override def toString = ++ ""Gossip("" + ++ ""overview = "" + overview + ++ "", members = ["" + members.mkString("", "") + ++ ""], meta = ["" + meta.mkString("", "") + ++ ""], version = "" + version + ++ "")"" ++} ++ ++/** ++ * FSM actor managing the different cluster nodes states. ++ * Single instance - e.g. serialized access to Node - message after message. ++ */ ++final class ClusterCommandDaemon(system: ActorSystem, node: Node) extends Actor with FSM[MemberStatus, Unit] { ++ ++ // start in JOINING ++ startWith(MemberStatus.Joining, Unit) ++ ++ // ======================== ++ // === IN JOINING === ++ when(MemberStatus.Joining) { ++ case Event(ClusterAction.Up, _) ⇒ ++ node.up() ++ goto(MemberStatus.Up) ++ } ++ ++ // ======================== ++ // === IN UP === ++ when(MemberStatus.Up) { ++ case Event(ClusterAction.Down, _) ⇒ ++ node.downing() ++ goto(MemberStatus.Down) ++ ++ case Event(ClusterAction.Leave, _) ⇒ ++ node.leaving() ++ goto(MemberStatus.Leaving) ++ ++ case Event(ClusterAction.Exit, _) ⇒ ++ node.exiting() ++ goto(MemberStatus.Exiting) ++ ++ case Event(ClusterAction.Remove, _) ⇒ ++ node.removing() ++ goto(MemberStatus.Removed) ++ } ++ ++ // ======================== ++ // === IN LEAVING === ++ when(MemberStatus.Leaving) { ++ case Event(ClusterAction.Down, _) ⇒ ++ node.downing() ++ goto(MemberStatus.Down) ++ ++ case Event(ClusterAction.Remove, _) ⇒ ++ node.removing() ++ goto(MemberStatus.Removed) ++ } ++ ++ // ======================== ++ // === IN EXITING === ++ when(MemberStatus.Exiting) { ++ case Event(ClusterAction.Remove, _) ⇒ ++ node.removing() ++ goto(MemberStatus.Removed) ++ } ++ ++ // ======================== ++ // === IN DOWN === ++ when(MemberStatus.Down) { ++ // FIXME How to transition from DOWN => JOINING when node comes back online. Can't just listen to Gossip message since it is received be another actor. How to fix this? ++ case Event(ClusterAction.Remove, _) ⇒ ++ node.removing() ++ goto(MemberStatus.Removed) ++ } ++ ++ // ======================== ++ // === IN REMOVED === ++ when(MemberStatus.Removed) { ++ case command ⇒ ++ log.warning(""Removed node [{}] received cluster command [{}]"", system.name, command) ++ stay ++ } ++ ++ // ======================== ++ // === GENERIC AND UNHANDLED COMMANDS === ++ whenUnhandled { ++ // should be able to handle Join in any state ++ case Event(ClusterAction.Join(address), _) ⇒ ++ node.joining(address) ++ stay ++ ++ case Event(command, _) ⇒ { ++ log.warning(""Unhandled command [{}] in state [{}]"", command, stateName) ++ stay ++ } ++ } ++} ++ ++/** ++ * Pooled and routed wit N number of configurable instances. ++ * Concurrent access to Node. ++ */ ++final class ClusterGossipDaemon(system: ActorSystem, node: Node) extends Actor { ++ val log = Logging(system, ""ClusterGossipDaemon"")","WDYM? Are you ironic? What is wrong? Please provide understandable feedback. +",cf3fa9fa3ce9e9312db0922370c93ce1af9db7c8 +434677,2,"Yeah, I’m feeling so BAD today.""",2012-02-09 09:25:00,rkuhn,akka,akka,,https://github.com/akka/akka-core/pull/317#discussion_r434677,2012-02-09T20:25:00Z,2012-02-10T13:17:34Z,rkuhn,CONTRIBUTOR,akka-actor/src/main/scala/akka/routing/Routing.scala,,,,,1,"@@ -30,14 +31,77 @@ private[akka] class RoutedActorRef(_system: ActorSystemImpl, _props: Props, _sup + _supervisor, + _path) { + +- private val routeeProps = _props.copy(routerConfig = NoRouter) +- private val resizeProgress = new AtomicBoolean ++ /* ++ * CAUTION: RoutedActorRef is PROBLEMATIC ++ * ====================================== ++ * ++ * We are constructing/assembling the children outside of the scope of the ++ * Router actor, inserting them in its childrenRef list, which is not at all ++ * synchronized. This is done exactly once at start-up, all other accesses ++ * are done from the Router actor. This means that the only thing which is ++ * really hairy is making sure that the Router does not touch its childrenRefs ++ * before we are done with them: create a locked latch really early (hence the ++ * override of newActorCell) and use that to block the Router constructor for ++ * as long as it takes to setup the RoutedActorRef itself. ++ */ ++ private[akka] var routeReady: ReentrantLock = _ ++ override def newActorCell( ++ system: ActorSystemImpl, ++ ref: InternalActorRef, ++ props: Props, ++ supervisor: InternalActorRef, ++ receiveTimeout: Option[Duration]): ActorCell = { ++ /* ++ * TODO RK: check that this really sticks, since this is executed before ++ * the constructor of RoutedActorRef is executed (invoked from ++ * LocalActorRef); works on HotSpot and JRockit. ++ */ ++ routeReady = new ReentrantLock ++ routeReady.lock() ++ super.newActorCell(system, ref, props, supervisor, receiveTimeout) ++ } ++ ++ private[akka] val routerConfig = _props.routerConfig ++ private[akka] val routeeProps = _props.copy(routerConfig = NoRouter) ++ private[akka] val resizeProgress = new AtomicBoolean + private val resizeCounter = new AtomicLong + + @volatile + private var _routees: IndexedSeq[ActorRef] = IndexedSeq.empty[ActorRef] // this MUST be initialized during createRoute + def routees = _routees + ++ private[akka] var routeeProvider: RouteeProvider = _ ++ val route = ++ try { ++ routeeProvider = routerConfig.createRouteeProvider(actorContext) ++ val r = routerConfig.createRoute(routeeProps, routeeProvider) ++ // initial resize, before message send ++ resize() ++ r ++ } finally routeReady.unlock() // unblock Router’s constructor","Yeah, I’m feeling so BAD today. +",36247b10fe79c8aa6ec878eaf4946c2cd1b65084 +436775,0,"What exactly (and I mean really the details) is the test meant to ensure? The current implementation of the test fails if any resize() call does not lead to an actual Resize event, which is definitely flawed. And hacking it so that the test works (by doin""",2012-02-09 20:17:40,rkuhn,akka,akka,,https://github.com/akka/akka-core/pull/317#discussion_r436775,2012-02-10T07:17:40Z,2012-02-10T13:17:34Z,rkuhn,CONTRIBUTOR,akka-actor-tests/src/test/scala/akka/routing/ResizerSpec.scala,,,,,1,"@@ -123,7 +123,15 @@ class ResizerSpec extends AkkaSpec(ResizerSpec.config) with DefaultTimeout with + current.routees.size must be(2) + } + +- ""resize when busy"" in { ++ /* ++ * TODO RK This test seems invalid to me, because it relies on that no resize() event is lost; ++ * this currently fails because I made resize() asynchronous (by sending a message to the ++ * Router), but it could also fail for concurrent send operations, i.e. when one of thread ++ * fails the resizeInProgress.compareAndSet(false, true) check. ++ * ++ * Either the test must be fixed/removed or resize() must be changed to be blocking. ++ */ ++ ""resize when busy"" ignore {","What exactly (and I mean really the details) is the test meant to ensure? The current implementation of the test fails if any resize() call does not lead to an actual Resize event, which is definitely flawed. And hacking it so that the test works (by doing some blocking) misses the point, IMHO, because that is not what user code would do. +",36247b10fe79c8aa6ec878eaf4946c2cd1b65084 +457023,0,"This way you encode a default value directly. We have made an effort to put all defaults into `reference.conf` to keep them central (and testable). val dispatcher = context.system.settings.config.getConfig(context.props.dispatcher) val config = d""",2012-02-16 02:18:22,rkuhn,akka,akka,,https://github.com/akka/akka-core/pull/307#discussion_r457023,2012-02-16T13:18:22Z,2012-02-28T09:22:30Z,rkuhn,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/Stash.scala,,,,,1,"@@ -0,0 +1,135 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++package akka.actor ++ ++import akka.dispatch.{ Envelope, DequeBasedMessageQueue } ++import akka.AkkaException ++ ++/** ++ * The `Stash` trait enables an actor to temporarily stash away messages that can not or ++ * should not be handled using the actor's current behavior. ++ *

++ * Example: ++ *

++ *    class ActorWithProtocol extends Actor with Stash {
++ *      def receive = {
++ *        case ""open"" ⇒
++ *          unstashAll {
++ *            case ""write"" ⇒ // do writing...
++ *            case ""close"" ⇒
++ *              unstashAll()
++ *              context.unbecome()
++ *            case msg ⇒ stash()
++ *          }
++ *        case ""done"" ⇒ // done
++ *        case msg    ⇒ stash()
++ *      }
++ *    }
++ *  
++ * ++ * Note that the `Stash` trait can only be used together with actors that have a deque-based ++ * mailbox. Actors can be configured to use a deque-based mailbox using a configuration like ++ * the following (see the documentation on dispatchers on how to configure a custom ++ * dispatcher): ++ *
++ *  akka {
++ *    actor {
++ *      my-custom-dispatcher {
++ *        mailbox-type = ""akka.dispatch.UnboundedDequeBasedMailbox""
++ *      }
++ *    }
++ *  }
++ *  
++ */ ++trait Stash extends Actor { ++ this: Actor ⇒ ++ ++ /* The private stash of the actor. It is only accessible using `stash()` and ++ * `unstashAll()`. ++ */ ++ private var theStash = Vector.empty[Envelope] ++ ++ /* The capacity of the stash. Either configured in the actor's dispatcher config, or ++ * `Int.MaxValue`. ++ */ ++ private val capacity = ++ try context.system.settings.config.getConfig(context.props.dispatcher).getInt(""stash-capacity"") ++ catch { ++ case _ ⇒ Int.MaxValue ++ }","This way you encode a default value directly. We have made an effort to put all defaults into `reference.conf` to keep them central (and testable). + +``` +val dispatcher = context.system.settings.config.getConfig(context.props.dispatcher) +val config = dispatcher.withFallback(context.system.settings.config.getConfig(""akka.actor.default-dispatcher"")) +config.getInt(""stash-capacity"") +``` + +which will never fail because there is a default in the default-dispatcher section. +",8ea949857b39388ac25bdc08df7feee3757f3ee9 +416655,1,"@VladimirMangos when you supply """"/dev/rsa"""" as commit author in git you instead put full path to git bins plus /dev/rsa :D lol can be seen in twitter or here: https://github.com/mangos/mangos/commit/6d0667fb72827b7ad23096dc04def141c12ecaae.patch""",2012-02-03 23:34:19,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/297#discussion_r416655,2012-02-04T10:34:19Z,2012-02-05T08:20:16Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/AkkaException.scala,,,,,1,"@@ -7,6 +7,26 @@ package akka + import akka.actor.newUuid + import java.net.{ InetAddress, UnknownHostException } + ++object AkkaException { ++ val hostname = try InetAddress.getLocalHost.getHostAddress catch { case e: UnknownHostException ⇒ ""unknown"" } ++ ++ def toStringWithStackTrace(throwable: Throwable): String = { ++ if (throwable eq null) ""Unknown Exception""","Technically ""unknown throwable"" +",42f5af7fb011059d8098532493eb13ec3116c7e5 +392257,2,"I don't like this at all. It's the provider who should provide these, don't like the leakage.""",2012-01-27 04:45:37,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/275#discussion_r392257,2012-01-27T15:45:37Z,2012-01-30T10:58:22Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorRef.scala,,355.0,,,32,"@@ -349,6 +349,15 @@ case class SerializedActorRef(path: String) { + } + } + ++object SerializedActorRef { ++ def apply(path: ActorPath): SerializedActorRef = { ++ Serialization.currentTransportAddress.value match { ++ case null ⇒ new SerializedActorRef(path.toString)","I don't like this at all. It's the provider who should provide these, don't like the leakage. +",4fb0858e557232e5f4a7e5b364d1697c0e21bdd1 +388691,0,"Has Derek signed the CLA?""",2012-01-26 06:45:26,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/273#discussion_r388691,2012-01-26T17:45:26Z,2012-01-26T17:45:26Z,viktorklang,CONTRIBUTOR,akka-docs/java/fault-tolerance-sample.rst,,8.0,,,8,"@@ -1,5 +1,51 @@ + .. _fault-tolerance-sample-java: + ++Diagrams of the Fault Tolerance Sample (Java) ++---------------------------------------------- ++ ++.. image:: ../images/faulttolerancesample-normal-flow.png ++ ++*The above diagram illustrates the normal message flow.*","Has Derek signed the CLA? +",f8741c326e881d05b6b9d89b1345c62dbfbaa226 +373889,1,"good point, will do, including specific section in migration docs""",2012-01-21 02:39:47,rkuhn,akka,akka,,https://github.com/akka/akka-core/pull/241#discussion_r373889,2012-01-21T13:39:47Z,2012-01-23T17:25:54Z,rkuhn,CONTRIBUTOR,akka-actor-migration/src/main/scala/akka/migration/package.scala,,36.0,,,6,"@@ -31,4 +31,7 @@ package object migration { + def stop(): Unit = GlobalActorSystem.stop(actorRef) + } + ++ implicit def ask(actorRef: ActorRef) = new akka.migration.AskableActorRef(actorRef) ++ def ask(actorRef: ActorRef, message: Any)(implicit timeout: Timeout = null): Future[Any] = akka.pattern.ask(actorRef, message)(timeout) ++","good point, will do, including specific section in migration docs +",9d7ed5eba16152d15269bf4f626260432359c0d4 +289597,2,"I think it's really bad, especially with PinnedDispatchers, since they create a new Dispatcher for every actor. We must fix this""",2011-12-13 02:16:42,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/149#discussion_r289597,2011-12-13T13:16:42Z,2011-12-13T14:05:16Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala,,78.0,,,1,"@@ -62,9 +69,30 @@ class Dispatchers(val settings: ActorSystem.Settings, val prerequisites: Dispatc + + val defaultDispatcherConfig = settings.config.getConfig(""akka.actor.default-dispatcher"") + +- // TODO PN Shouldn't we fail hard if default-dispatcher is wrong? +- lazy val defaultGlobalDispatcher = +- from(defaultDispatcherConfig) getOrElse newDispatcher(""AkkaDefaultGlobalDispatcher"", 1, MailboxType).build ++ lazy val defaultGlobalDispatcher: MessageDispatcher = ++ from(defaultDispatcherConfig) getOrElse { ++ throw new ConfigurationException(""Wrong configuration [akka.actor.default-dispatcher]"") ++ } ++ ++ private val dispatchers = new ConcurrentHashMap[String, MessageDispatcher]","I think it's really bad, especially with PinnedDispatchers, since they create a new Dispatcher for every actor. +We must fix this +",7a17eb00bf7043b8b89839aecebf0e66b91dd9e9 +171073,0,"But you're calling out to the methods of the Actor, which is a violation of the ActorModel, since the Actor could be shut down or it's fields might be invisible from a JMM perspective, why not put the connect, bind etc as methods inside the select-functio""",2011-10-13 19:35:23,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/92#discussion_r171073,2011-10-14T07:35:23Z,2011-10-19T18:11:55Z,viktorklang,CONTRIBUTOR,akka-zeromq/src/main/scala/akka/zeromq/ConcurrentSocketActor.scala,,,,,1,"@@ -0,0 +1,113 @@ ++/** ++ * Copyright (C) 2009-2011 Typesafe Inc. ++ */ ++package akka.zeromq ++ ++import akka.actor.{Actor, ActorRef} ++import akka.dispatch.MessageDispatcher ++import akka.zeromq.SocketType._ ++import java.util.concurrent.atomic.AtomicReference ++import org.zeromq.ZMQ.{Socket, Poller} ++import org.zeromq.{ZMQ => JZMQ} ++import scala.annotation.tailrec ++import scala.collection.mutable.MutableList ++ ++private[zeromq] class ConcurrentSocketActor( ++ context: Context, ++ socketType: SocketType, ++ listener: Option[ActorRef], ++ deserializer: Deserializer, ++ dispatcher: MessageDispatcher) extends Actor { ++ private val pollTimeoutMsec = 10 ++ private val requests = new AtomicReference(List.empty[Request]) ++ private val socket: Socket = context.socket(socketType) ++ private val poller: Poller = context.poller ++ private var socketClosed: Boolean = false ++ self.dispatcher = dispatcher ++ poller.register(socket, Poller.POLLIN) ++ private val select = { () => ++ if (!socketClosed) { ++ if (poller.poll(pollTimeoutMsec) > 0) { ++ if (poller.pollin(0)) { ++ receiveFrames match { ++ case frames if (frames.length > 0) => listener.foreach { listener => ++ if (listener.isRunning) ++ listener ! deserializer(frames) ++ } ++ } ++ } ++ } ++ requests.getAndSet(Nil).foreach {","But you're calling out to the methods of the Actor, which is a violation of the ActorModel, since the Actor could be shut down or it's fields might be invisible from a JMM perspective, why not put the connect, bind etc as methods inside the select-function? (or are they used internally in the actor as well?= +",826495e912557a63835cd0f79ae1a2acd3525811 +506788,0,"it is only used in test, moved it there""",2012-03-01 03:10:58,RayRoestenburg,akka,akka,,https://github.com/akka/akka-core/pull/344#discussion_r506788,2012-03-01T14:10:58Z,2012-03-20T12:17:27Z,RayRoestenburg,CONTRIBUTOR,akka-camel/src/main/scala/akka/camel/Consumer.scala,,,,,1,"@@ -1,144 +1,67 @@ + /** +- * Copyright (C) 2009-2010 Typesafe Inc. ++ * Copyright (C) 2009-2012 Typesafe Inc. + */ + + package akka.camel + ++import internal.component.DurationTypeConverter + import org.apache.camel.model.{ RouteDefinition, ProcessorDefinition } + + import akka.actor._ ++import akka.util.Duration ++import akka.util.duration._ + + /** + * Mixed in by Actor implementations that consume message from Camel endpoints. + * + * @author Martin Krasser + */ +-trait Consumer { this: Actor ⇒ +- import RouteDefinitionHandler._ ++trait Consumer extends Actor with ConsumerConfig { + +- /** +- * The default route definition handler is the identity function +- */ +- private[camel] var routeDefinitionHandler: RouteDefinitionHandler = identity +- +- /** +- * Returns the Camel endpoint URI to consume messages from. +- */ + def endpointUri: String ++ protected[this] implicit lazy val camel = CamelExtension(context.system) + +- /** +- * Determines whether two-way communications between an endpoint and this consumer actor +- * should be done in blocking or non-blocking mode (default is non-blocking). This method +- * doesn't have any effect on one-way communications (they'll never block). +- */ +- def blocking = false +- +- /** +- * Determines whether one-way communications between an endpoint and this consumer actor +- * should be auto-acknowledged or system-acknowledged. +- */ +- def autoack = true +- +- /** +- * Sets the route definition handler for creating a custom route to this consumer instance. +- */ +- def onRouteDefinition(h: RouteDefinition ⇒ ProcessorDefinition[_]): Unit = onRouteDefinition(from(h)) +- +- /** +- * Sets the route definition handler for creating a custom route to this consumer instance. +- *

+- * Java API. +- */ +- def onRouteDefinition(h: RouteDefinitionHandler): Unit = routeDefinitionHandler = h ++ camel.registerConsumer(endpointUri, this, activationTimeout) + } + +-/** +- * Java-friendly Consumer. +- * +- * Subclass this abstract class to create an MDB-style untyped consumer actor. This +- * class is meant to be used from Java. +- * +- * @author Martin Krasser +- */ +-abstract class UntypedConsumerActor extends UntypedActor with Consumer { +- final override def endpointUri = getEndpointUri +- final override def blocking = isBlocking +- final override def autoack = isAutoack ++trait ConsumerConfig { ++ //TODO: Explain the parameters better with some examples! + + /** +- * Returns the Camel endpoint URI to consume messages from. ++ * How long should the actor wait for activation before it fails. + */ +- def getEndpointUri(): String ++ def activationTimeout: Duration = 10 seconds + + /** +- * Determines whether two-way communications between an endpoint and this consumer actor +- * should be done in blocking or non-blocking mode (default is non-blocking). This method +- * doesn't have any effect on one-way communications (they'll never block). ++ * When endpoint is out-capable (can produce responses) replyTimeout is the maximum time ++ * the endpoint can take to send the response before the message exchange fails. It defaults to 1 minute. ++ * This setting is used for out-capable, in-only, manually acknowledged communication. ++ * When the blocking is set to Blocking replyTimeout is ignored. + */ +- def isBlocking() = super.blocking ++ def replyTimeout: Duration = 1 minute + + /** + * Determines whether one-way communications between an endpoint and this consumer actor +- * should be auto-acknowledged or system-acknowledged. ++ * should be auto-acknowledged or application-acknowledged. ++ * This flag has only effect when exchange is in-only. + */ +- def isAutoack() = super.autoack +-} +- +-/** +- * A callback handler for route definitions to consumer actors. +- * +- * @author Martin Krasser +- */ +-trait RouteDefinitionHandler { +- def onRouteDefinition(rd: RouteDefinition): ProcessorDefinition[_] +-} ++ def autoack: Boolean = true + +-/** +- * The identity route definition handler. +- * +- * @author Martin Krasser +- * +- */ +-class RouteDefinitionIdentity extends RouteDefinitionHandler { +- def onRouteDefinition(rd: RouteDefinition) = rd +-} +- +-/** +- * @author Martin Krasser +- */ +-object RouteDefinitionHandler { + /** +- * Returns the identity route definition handler ++ * The route definition handler for creating a custom route to this consumer instance. + */ +- val identity = new RouteDefinitionIdentity ++ //TODO: write a test confirming onRouteDefinition gets called ++ def onRouteDefinition(rd: RouteDefinition): ProcessorDefinition[_] = rd + +- /** +- * Created a route definition handler from the given function. +- */ +- def from(f: RouteDefinition ⇒ ProcessorDefinition[_]) = new RouteDefinitionHandler { +- def onRouteDefinition(rd: RouteDefinition) = f(rd) +- } ++ private[camel] def toCamelParameters: String = ""autoack=%s&replyTimeout=%s"" format (autoack, DurationTypeConverter.toString(replyTimeout)) + } + +-/** +- * @author Martin Krasser +- */ +-private[camel] object Consumer { +- /** +- * Applies a function f to actorRef if actorRef +- * references a consumer actor. A valid reference to a consumer actor is a local actor +- * reference with a target actor that implements the Consumer trait. The +- * target Consumer instance is passed as argument to f. This +- * method returns None if actorRef is not a valid reference +- * to a consumer actor, Some contained the return value of f +- * otherwise. +- */ +- def withConsumer[T](actorRef: ActorRef)(f: Consumer ⇒ T): Option[T] = actorRef match { +- case l: LocalActorRef ⇒ +- l.underlyingActorInstance match { +- case c: Consumer ⇒ Some(f(c)) +- case _ ⇒ None +- } +- case _ ⇒ None +- } ++trait ManualAckConsumer extends Consumer {","it is only used in test, moved it there +",f74616f828d3e31724d768dd86ce05af85d97ade +465397,1,"Yup, agreed, and indeed I was mislead by the other issue (which was the UrlMatcher not decoding). I tested and it seems to work all good now, with full encoding. I just decode the / back and turn %20 into + because it looks better and seems to work just fi""",2012-02-19 03:58:35,rkuhn,akka,akka,,https://github.com/akka/akka-core/pull/330#discussion_r465397,2012-02-19T14:58:35Z,2012-02-19T14:58:35Z,rkuhn,CONTRIBUTOR,akka-actor/src/main/scala/akka/dispatch/Future.scala,,357.0,,,22,"@@ -353,33 +354,33 @@ object Future { + } + + private val _taskStack = new ThreadLocal[Stack[() ⇒ Unit]]() +- private val _executionContext = new ThreadLocal[ExecutionContext]() ++ private val _executionContext = new DynamicVariable[ExecutionContext](null)","I knew it! There was something which successfully hid amidst the shadows. +",258d710dab3b9532275ca5412bd33fcde124965d +392351,0,"it's documented on ActorPath, and it's used for cheaply injecting the transport address into its string rep (for local Addresses)""",2012-01-27 05:10:53,rkuhn,akka,akka,,https://github.com/akka/akka-core/pull/275#discussion_r392351,2012-01-27T16:10:53Z,2012-01-30T10:58:22Z,rkuhn,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorPath.scala,,120.0,,,37,"@@ -105,6 +117,10 @@ final case class RootActorPath(address: Address, name: String = ""/"") extends Act + + override val toString = address + name + ++ def toStringWithAddress(addr: Address): String =","it's documented on ActorPath, and it's used for cheaply injecting the transport address into its string rep (for local Addresses) +",4fb0858e557232e5f4a7e5b364d1697c0e21bdd1 +362454,2,"This is most likely a bad default""",2012-01-18 01:00:15,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/217#discussion_r362454,2012-01-18T12:00:15Z,2012-01-18T16:57:18Z,viktorklang,CONTRIBUTOR,akka-camel/src/main/scala/akka/camel/Consumer.scala,,40.0,,,1,"@@ -1,144 +1,71 @@ + /** +- * Copyright (C) 2009-2010 Typesafe Inc. ++ * Copyright (C) 2009-2010 Scalable Solutions AB + */ + + package akka.camel + +-import org.apache.camel.model.{ RouteDefinition, ProcessorDefinition } ++import org.apache.camel.model.{RouteDefinition, ProcessorDefinition} + + import akka.actor._ ++import akka.util.Duration ++import akka.util.duration._ + + /** + * Mixed in by Actor implementations that consume message from Camel endpoints. + * + * @author Martin Krasser + */ +-trait Consumer { this: Actor ⇒ +- import RouteDefinitionHandler._ ++trait Consumer extends Actor with ConsumerConfig{ + +- /** +- * The default route definition handler is the identity function +- */ +- private[camel] var routeDefinitionHandler: RouteDefinitionHandler = identity ++ def endpointUri : String + +- /** +- * Returns the Camel endpoint URI to consume messages from. +- */ +- def endpointUri: String +- +- /** +- * Determines whether two-way communications between an endpoint and this consumer actor +- * should be done in blocking or non-blocking mode (default is non-blocking). This method +- * doesn't have any effect on one-way communications (they'll never block). +- */ +- def blocking = false ++ CamelExtension(context.system).registerConsumer(endpointUri, this, activationTimeout) ++} + +- /** +- * Determines whether one-way communications between an endpoint and this consumer actor +- * should be auto-acknowledged or system-acknowledged. +- */ +- def autoack = true + +- /** +- * Sets the route definition handler for creating a custom route to this consumer instance. +- */ +- def onRouteDefinition(h: RouteDefinition ⇒ ProcessorDefinition[_]): Unit = onRouteDefinition(from(h)) ++trait ConsumerConfig{ ++ //TODO: Explain the parameters better with some examples! + + /** +- * Sets the route definition handler for creating a custom route to this consumer instance. +- *

+- * Java API. ++ * How long should the actor wait for activation before it fails. + */ +- def onRouteDefinition(h: RouteDefinitionHandler): Unit = routeDefinitionHandler = h +-} +- +-/** +- * Java-friendly Consumer. +- * +- * Subclass this abstract class to create an MDB-style untyped consumer actor. This +- * class is meant to be used from Java. +- * +- * @author Martin Krasser +- */ +-abstract class UntypedConsumerActor extends UntypedActor with Consumer { +- final override def endpointUri = getEndpointUri +- final override def blocking = isBlocking +- final override def autoack = isAutoack ++ def activationTimeout: Duration = 10 seconds + + /** +- * Returns the Camel endpoint URI to consume messages from. ++ * When endpoint is outCapable (can produce responses) outTimeout is the maximum time ++ * the endpoint can take to send the response before the message exchange fails. It defaults to Int.MaxValue seconds. ++ * It can be also overwritten by setting @see blocking property + */ +- def getEndpointUri(): String ++ def outTimeout : Duration = Int.MaxValue seconds","This is most likely a bad default +",457354db8ba6b42dbacc246c11f0ff15e38ebab4 +362749,0,"This version will silently update and break the checksum, which is why we pull a specific version out of Google Code instead. Maybe make a new patch that uses an updated specific Google Code revision for `url`.""",2012-01-18 02:21:27,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/217#discussion_r362749,2012-01-18T13:21:27Z,2012-01-18T16:57:20Z,viktorklang,CONTRIBUTOR,akka-camel/src/on-hold/test/scala/akka/camel/component/ActorComponentFeatureTest.scala,,3.0,,,4,"@@ -1,22 +1,22 @@ + package akka.camel.component + +-import java.util.concurrent.{ TimeUnit, CountDownLatch } ++import java.util.concurrent.{TimeUnit, CountDownLatch}","Does any of the code after this even compile? I'd say, no? +",457354db8ba6b42dbacc246c11f0ff15e38ebab4 +365589,0,"Ok - I take it. Forgive my ignorance - what's wrong with starting children that way? Is this violating the rule of not sending behaviour to an actor?""",2012-01-18 14:17:07,piotrga,akka,akka,,https://github.com/akka/akka-core/pull/217#discussion_r365589,2012-01-19T01:17:07Z,2012-01-19T01:17:07Z,piotrga,CONTRIBUTOR,akka-camel/src/main/scala/akka/camelexamples/_2_SupervisedConsumers.scala,,26.0,,,26,"@@ -0,0 +1,37 @@ ++package akka.camelexamples ++ ++import akka.actor.{PoisonPill, Terminated, Props, ActorSystem, Actor} ++import ExamplesSupport._ ++import RichString._ ++ ++ ++object SupervisedConsumersExample extends App{ ++ ++ val system = ActorSystem(""test1"") ++ ++ system.actorOf(Props(new Actor{ ++ context.watch(context.actorOf(Props(faultHandler = retry3xWithin1s, creator = () => new EndpointManager))) ++ protected def receive = { ++ case Terminated(ref) => system.shutdown() ++ } ++ })) ++ ++ ++ ""data/input/CamelConsumer/file1.txt"" << ""test data ""+math.random ++} ++ ++class EndpointManager extends Actor { ++ ++ override def preStart() { ++ self ! Props[SysOutConsumer]","Ok - I take it. +Forgive my ignorance - what's wrong with starting children that way? +Is this violating the rule of not sending behaviour to an actor? +",457354db8ba6b42dbacc246c11f0ff15e38ebab4 +344791,0,"In the end it does actorFor so it should be fine with ActorPath. Will try to change that in separate refactoring. On Wed, Jan 11, 2012 at 7:36 PM, viktorklang < reply@reply.github.com > wrote: > > + * Please note that providing both 'nrOfInstances' and """,2012-01-11 09:41:37,patriknw,akka,akka,,https://github.com/akka/akka-core/pull/209#discussion_r344791,2012-01-11T20:41:37Z,2012-01-12T08:54:25Z,patriknw,CONTRIBUTOR,akka-remote/src/main/scala/akka/routing/RemoteRouters.scala,,103.0,,,21,"@@ -83,6 +83,33 @@ case class RemoteRandomRouter(nrOfInstances: Int, routees: Iterable[String], ove + } + + /** ++ * A Router that tries to send to routee with fewest messages in mailbox. ++ *
++ * Please note that providing both 'nrOfInstances' and 'routees' does not make logical sense as this means ++ * that the random router should both create new actors and use the 'routees' actor(s). ++ * In this case the 'nrOfInstances' will be ignored and the 'routees' will be used. ++ *
++ * The configuration parameter trumps the constructor arguments. This means that ++ * if you provide either 'nrOfInstances' or 'routees' to during instantiation they will ++ * be ignored if the 'nrOfInstances' is defined in the configuration file for the actor being used. ++ */ ++case class RemoteSmallestMailboxRouter(nrOfInstances: Int, routees: Iterable[String], override val resizer: Option[Resizer] = None) ++ extends RemoteRouterConfig with SmallestMailboxLike { ++ ++ /** ++ * Constructor that sets the routees to be used. ++ * Java API ++ */ ++ def this(n: Int, t: java.lang.Iterable[String]) = this(n, t.asScala)","In the end it does actorFor so it should be fine with ActorPath. Will try +to change that in separate refactoring. + +On Wed, Jan 11, 2012 at 7:36 PM, viktorklang < +reply@reply.github.com + +> wrote: +> +> > - \* Please note that providing both 'nrOfInstances' and 'routees' does +> > not make logical sense as this means +> > - \* that the random router should both create new actors and use the +> > 'routees' actor(s). +> > - \* In this case the 'nrOfInstances' will be ignored and the 'routees' +> > will be used. +> > - \*
+> > - \* The configuration parameter trumps the constructor arguments. +> > This means that +> > - \* if you provide either 'nrOfInstances' or 'routees' to during +> > instantiation they will +> > - \* be ignored if the 'nrOfInstances' is defined in the configuration +> > file for the actor being used. +> > - */ +> > +case class RemoteSmallestMailboxRouter(nrOfInstances: Int, routees: +> > Iterable[String], override val resizer: Option[Resizer] = None) +> > - extends RemoteRouterConfig with SmallestMailboxLike { +> > + +> > - /** +> > - \* Constructor that sets the routees to be used. +> > - \* Java API +> > - */ +> > - def this(n: Int, t: java.lang.Iterable[String]) = this(n, t.asScala) +> +> Why is this an Iterable of Strings and not an Iterable of ActorPath? +> +> --- +> +> Reply to this email directly or view it on GitHub: +> https://github.com/jboner/akka/pull/209/files#r344268 + +## + +Patrik Nordwall +Typesafe http://typesafe.com/ - The modern software stack for +applications that scale +Twitter: @patriknw +",2399f02531ce1d8fda33f5f65bbf951f2671976a +289647,0,"WeakHashMap is bad for gc, but ticket is created #1494 I leave it with a FIXME refererence to that ticket. On Tue, Dec 13, 2011 at 2:32 PM, viktorklang < reply@reply.github.com > wrote: > > @@ -62,9 +69,30 @@ class Dispatchers(val settings: ActorSystem.""",2011-12-13 02:56:14,patriknw,akka,akka,,https://github.com/akka/akka-core/pull/149#discussion_r289647,2011-12-13T13:56:14Z,2011-12-13T14:05:16Z,patriknw,CONTRIBUTOR,akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala,,78.0,,,1,"@@ -62,9 +69,30 @@ class Dispatchers(val settings: ActorSystem.Settings, val prerequisites: Dispatc + + val defaultDispatcherConfig = settings.config.getConfig(""akka.actor.default-dispatcher"") + +- // TODO PN Shouldn't we fail hard if default-dispatcher is wrong? +- lazy val defaultGlobalDispatcher = +- from(defaultDispatcherConfig) getOrElse newDispatcher(""AkkaDefaultGlobalDispatcher"", 1, MailboxType).build ++ lazy val defaultGlobalDispatcher: MessageDispatcher = ++ from(defaultDispatcherConfig) getOrElse { ++ throw new ConfigurationException(""Wrong configuration [akka.actor.default-dispatcher]"") ++ } ++ ++ private val dispatchers = new ConcurrentHashMap[String, MessageDispatcher]","WeakHashMap is bad for gc, but ticket is created #1494 +I leave it with a FIXME refererence to that ticket. + +On Tue, Dec 13, 2011 at 2:32 PM, viktorklang < +reply@reply.github.com + +> wrote: +> +> > @@ -62,9 +69,30 @@ class Dispatchers(val settings: ActorSystem.Settings, +> > val prerequisites: Dispatc +> > +> > val defaultDispatcherConfig = +> > settings.config.getConfig(""akka.actor.default-dispatcher"") +> > - // TODO PN Shouldn't we fail hard if default-dispatcher is wrong? +> > - lazy val defaultGlobalDispatcher = +> > - from(defaultDispatcherConfig) getOrElse +> > newDispatcher(""AkkaDefaultGlobalDispatcher"", 1, MailboxType).build +> > - lazy val defaultGlobalDispatcher: MessageDispatcher = +> > - from(defaultDispatcherConfig) getOrElse { +> > - throw new ConfigurationException(""Wrong configuration +> > [akka.actor.default-dispatcher]"") +> > - } +> > + +> > - private val dispatchers = new ConcurrentHashMap[String, +> > MessageDispatcher] +> +> No, it's probably for the best that pinned dispatchers aren't registered +> there. +> +> Open a ticket about making sure that it gets cleaned up and assign it for +> 2.0, we might want to use a WeakHashMap or equivalent. +> +> --- +> +> Reply to this email directly or view it on GitHub: +> https://github.com/jboner/akka/pull/149/files#r289614 + +## + +Patrik Nordwall +Typesafe http://typesafe.com/ - Enterprise-Grade Scala from the Experts +Twitter: @patriknw +",7a17eb00bf7043b8b89839aecebf0e66b91dd9e9 +254337,0,"MAke it so that the dispatcher to be used is specified through the constructor, in that way it'll be easier to configure it later.""",2011-11-28 04:27:04,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/127#discussion_r254337,2011-11-28T15:27:04Z,2011-11-30T14:24:56Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala,,,,,1,"@@ -429,8 +429,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, system: ActorSystem) + private def createSingleTask(runnable: Runnable): TimerTask = + new TimerTask() { + def run(timeout: org.jboss.netty.akka.util.Timeout) { +- // FIXME: consider executing runnable inside main dispatcher to prevent blocking of scheduler +- runnable.run() ++ system.dispatcher.dispatchTask(() ⇒ runnable.run())","MAke it so that the dispatcher to be used is specified through the constructor, in that way it'll be easier to configure it later. +",b3107aed733958523abad1ea386d1de95e6a421a +248167,0,"Netty""",2011-11-23 03:55:13,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/120#discussion_r248167,2011-11-23T14:55:13Z,2011-11-24T07:35:31Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/resources/akka-actor-reference.conf,,,,,1,"@@ -214,6 +214,21 @@ akka { + # } + } + ++ # Used to set the behavior of the scheduler. ++ # Changing the default values may change the system behavior drastically so make sure you know what you're doing! ++ # ++ scheduler { ++ # The HashedWheelTimer (HWT) implementation from Jetty is used as the default scheduler in the system.","Netty +",4a2a5123bfff655e8839d28846fe445d950f5934 +269717,0,"hashedWheelTimer.stop().asScala foreach execDirectly""",2011-12-05 02:19:14,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/119#discussion_r269717,2011-12-05T13:19:14Z,2011-12-05T21:48:29Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala,,,,,1,"@@ -471,12 +619,24 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, log: LoggingAdapter, + new TimerTask { + def run(timeout: org.jboss.netty.akka.util.Timeout) { + dispatcher.dispatchTask(f) +- timeout.getTimer.newTimeout(this, delay) ++ try timeout.getTimer.newTimeout(this, delay) catch { ++ case _: IllegalStateException ⇒ // stop recurring if timer is stopped ++ } + } + } + } + +- def close() = hashedWheelTimer.stop() ++ private def execDirectly(t: HWTimeout): Unit = { ++ try t.getTask.run(t) catch { ++ case e: InterruptedException ⇒ throw e ++ case e: Exception ⇒ log.error(e, ""exception while executing timer task"") ++ } ++ } ++ ++ def close() = { ++ import scala.collection.JavaConverters._ ++ hashedWheelTimer.stop().asScala foreach (t ⇒ execDirectly(t))","hashedWheelTimer.stop().asScala foreach execDirectly +",9d7597c7282711889d74bd9b4d7bdae5ea254104 +272492,0,"On Mon, Dec 5, 2011 at 3:32 PM, viktorklang < reply@reply.github.com > wrote: > > @@ -459,7 +605,9 @@ class DefaultScheduler(hashedWheelTimer: > HashedWheelTimer, log: LoggingAdapter, > > // Check if the receiver is still alive and kicking befor""",2011-12-05 20:55:48,patriknw,akka,akka,,https://github.com/akka/akka-core/pull/119#discussion_r272492,2011-12-06T07:55:48Z,2011-12-06T07:55:48Z,patriknw,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala,,612.0,,,633,"@@ -459,7 +605,9 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, log: LoggingAdapter, + // Check if the receiver is still alive and kicking before sending it a message and reschedule the task + if (!receiver.isTerminated) { + receiver ! message +- timeout.getTimer.newTimeout(this, delay) ++ try timeout.getTimer.newTimeout(this, delay) catch { ++ case _: IllegalStateException ⇒ // stop recurring if timer is stopped","On Mon, Dec 5, 2011 at 3:32 PM, viktorklang < +reply@reply.github.com + +> wrote: +> +> > @@ -459,7 +605,9 @@ class DefaultScheduler(hashedWheelTimer: +> > HashedWheelTimer, log: LoggingAdapter, +> > // Check if the receiver is still alive and kicking before +> > sending it a message and reschedule the task +> > if (!receiver.isTerminated) { +> > receiver ! message +> > - timeout.getTimer.newTimeout(this, delay) +> > - try timeout.getTimer.newTimeout(this, delay) catch { +> > - case _: IllegalStateException => // stop recurring if timer +> > is stopped +> +> Shouldn't this verify that the IllegalState was from it being stopped? + +If not already done, the IllegalStateException should be well documented in +the api of the Scheduler, because now we rely on that behavior for proper +dispatcher shutdown, and the Scheduler is (in theory) replaceable. + +> --- +> +> Reply to this email directly or view it on GitHub: +> https://github.com/jboner/akka/pull/119/files#r269820 + +## + +Patrik Nordwall +Typesafe http://typesafe.com/ - Enterprise-Grade Scala from the Experts +Twitter: @patriknw +",9d7597c7282711889d74bd9b4d7bdae5ea254104 +242131,1,"sexy""",2011-11-21 04:26:06,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/118#discussion_r242131,2011-11-21T15:26:06Z,2011-11-21T15:26:06Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/resources/akka-actor-reference.conf,,26.0,,,14,"@@ -25,7 +23,7 @@ akka { + # Dispatcher, (BalancingDispatcher, only valid when all actors using it are of the same type), + # A FQCN to a class inheriting MessageDispatcherConfigurator with a no-arg visible constructor + name = ""EventHandlerDispatcher"" # Optional, will be a generated UUID if omitted +- keep-alive-time = 60 # Keep alive time for threads ++ keep-alive-time = 60s # Keep alive time for threads","sexy +",e5f8a41cb85fe950df8de3f2f8abf3746c9d65b1 +228563,0,"Do you really want to force the size to know if empty?""",2011-11-14 11:20:37,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/110#discussion_r228563,2011-11-14T22:20:37Z,2011-11-15T13:40:37Z,viktorklang,CONTRIBUTOR,akka-durable-mailboxes/akka-file-mailbox/src/main/scala/akka/actor/mailbox/FiledBasedMailbox.scala,,62.0,,,81,"@@ -4,55 +4,63 @@ + + package akka.actor.mailbox + +-import akka.actor.LocalActorRef +-import akka.dispatch._ +-import akka.config.Config._ +-import akka.event.EventHandler +- + import org.apache.commons.io.FileUtils ++import akka.actor.ActorCell ++import akka.config.Configuration ++import akka.dispatch.Envelope ++import akka.event.Logging ++import akka.actor.ActorRef + +-/** +- * @author Jonas Bonér +- */ +-private[akka] object FileBasedMailboxUtil { +- val queuePath = config.getString(""akka.actor.mailbox.file-based.directory-path"", ""./_mb"") // /var/spool/akka ++object FileBasedMailbox { ++ def queuePath(config: Configuration): String = { ++ config.getString(""akka.actor.mailbox.file-based.directory-path"", ""./_mb"") // /var/spool/akka ++ } + } + +-class FileBasedMailbox(val owner: LocalActorRef) extends DurableExecutableMailbox(owner) { +- import FileBasedMailboxUtil._ ++class FileBasedMailbox(val owner: ActorCell) extends DurableMailbox(owner) with DurableMessageSerialization { ++ ++ val log = Logging(app, this) ++ ++ val queuePath = FileBasedMailbox.queuePath(owner.app.config) + + private val queue = try { + try { FileUtils.forceMkdir(new java.io.File(queuePath)) } catch { case e ⇒ {} } +- val queue = new filequeue.PersistentQueue(queuePath, name, config) ++ val queue = new filequeue.PersistentQueue(queuePath, name, owner.app.config, log) + queue.setup // replays journal + queue.discardExpired + queue + } catch { + case e: Exception ⇒ +- EventHandler.error(e, this, ""Could not create a file-based mailbox"") ++ log.error(e, ""Could not create a file-based mailbox"") + throw e + } + +- def enqueue(message: MessageInvocation) = { +- EventHandler.debug(this, ""\nENQUEUING message in file-based mailbox [%s]"".format(message)) +- queue.add(serialize(message)) ++ def enqueue(receiver: ActorRef, envelope: Envelope) { ++ log.debug(""ENQUEUING message in file-based mailbox [{}]"", envelope) ++ queue.add(serialize(envelope)) + } + +- def dequeue: MessageInvocation = try { ++ def dequeue(): Envelope = try { + val item = queue.remove + if (item.isDefined) { + queue.confirmRemove(item.get.xid) +- val messageInvocation = deserialize(item.get.data) +- EventHandler.debug(this, ""\nDEQUEUING message in file-based mailbox [%s]"".format(messageInvocation)) +- messageInvocation ++ val envelope = deserialize(item.get.data) ++ log.debug(""DEQUEUING message in file-based mailbox [{}]"", envelope) ++ envelope + } else null + } catch { + case e: java.util.NoSuchElementException ⇒ null + case e: Exception ⇒ +- EventHandler.error(e, this, ""Couldn't dequeue from file-based mailbox"") ++ log.error(e, ""Couldn't dequeue from file-based mailbox"") + throw e + } + ++ def numberOfMessages: Int = { ++ queue.length.toInt ++ } ++ ++ def hasMessages: Boolean = numberOfMessages > 0","Do you really want to force the size to know if empty? +",a6e75fb702df10eb00070b8631aca6f009f727d5 +221062,0,"If this is only used in one place for one usage I'd rather just use ConcurrentHashMap and make sure that whatever gets put into it only has identity equality defined""",2011-11-10 01:56:47,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/106#discussion_r221062,2011-11-10T12:56:47Z,2011-11-10T15:33:03Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/java/org/jboss/netty/akka/util/internal/ConcurrentIdentityHashMap.java,,51.0,,,51,"@@ -0,0 +1,1418 @@ ++/* ++ * Copyright 2009 Red Hat, Inc. ++ * ++ * Red Hat licenses this file to you under the Apache License, version 2.0 ++ * (the ""License""); you may not use this file except in compliance with the ++ * License. You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an ""AS IS"" BASIS, WITHOUT ++ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the ++ * License for the specific language governing permissions and limitations ++ * under the License. ++ */ ++/* ++ * Written by Doug Lea with assistance from members of JCP JSR-166 ++ * Expert Group and released to the public domain, as explained at ++ * http://creativecommons.org/licenses/publicdomain ++ */ ++package org.jboss.netty.akka.util.internal; ++ ++import java.util.AbstractCollection; ++import java.util.AbstractMap; ++import java.util.AbstractSet; ++import java.util.Collection; ++import java.util.ConcurrentModificationException; ++import java.util.Enumeration; ++import java.util.Hashtable; ++import java.util.Iterator; ++import java.util.Map; ++import java.util.NoSuchElementException; ++import java.util.Set; ++import java.util.concurrent.ConcurrentMap; ++import java.util.concurrent.locks.ReentrantLock; ++ ++ ++/** ++ * An alternative identity-comparing {@link java.util.concurrent.ConcurrentMap} which is similar to ++ * {@link java.util.concurrent.ConcurrentHashMap}. ++ * ++ * @author The Netty Project ++ * @author Doug Lea ++ * @author Jason T. Greene ++ * @author Trustin Lee ++ * @version $Rev: 2371 $, $Date: 2010-10-19 15:00:42 +0900 (Tue, 19 Oct 2010) $ ++ * ++ * @param the type of keys maintained by this map ++ * @param the type of mapped values ++ */ ++public final class ConcurrentIdentityHashMap extends AbstractMap","If this is only used in one place for one usage I'd rather just use ConcurrentHashMap and make sure that whatever gets put into it only has identity equality defined +",1577f8bcb32097e2e317302089d92fd417b69913 +489604,2,"doesn’t work: there is no system available while constructing MailboxType :-(""",2012-02-26 08:17:40,rkuhn,akka,akka,,https://github.com/akka/akka-core/pull/353#discussion_r489604,2012-02-26T19:17:40Z,2012-02-26T20:39:34Z,rkuhn,CONTRIBUTOR,akka-durable-mailboxes/akka-beanstalk-mailbox/src/main/scala/akka/actor/mailbox/BeanstalkBasedMailbox.scala,,,,,1,"@@ -27,9 +27,9 @@ class BeanstalkBasedMailboxType(config: Config) extends MailboxType { + /** + * @author Jonas Bonér + */ +-class BeanstalkBasedMessageQueue(_owner: ActorContext) extends DurableMessageQueue(_owner) with DurableMessageSerialization { ++class BeanstalkBasedMessageQueue(_owner: ActorContext, _config: Config) extends DurableMessageQueue(_owner) with DurableMessageSerialization { + +- private val settings = BeanstalkBasedMailboxExtension(owner.system) ++ private val settings = new BeanstalkMailboxSettings(owner.system, _config)","doesn’t work: there is no system available while constructing MailboxType :-( +",b4fcc3b2f2d7e534908057750d0086b9c6e20764 +488501,0,"removed def system from Camel trait, it is not needed in the end for the user. (you can always get to the system using the normal routes) Added a comment that Camel is shutdown when the associated ActorSystem that uses a Camel extension is shut down.""",2012-02-24 21:26:34,RayRoestenburg,akka,akka,,https://github.com/akka/akka-core/pull/344#discussion_r488501,2012-02-25T08:26:34Z,2012-03-20T12:17:25Z,RayRoestenburg,CONTRIBUTOR,akka-camel/src/main/scala/akka/camel/Camel.scala,,,,,1,"@@ -0,0 +1,84 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++ ++package akka.camel ++ ++import internal._ ++import akka.actor._ ++import org.apache.camel.{ ProducerTemplate, CamelContext } ++ ++//TODO complete this doc ++/** ++ * Camel trait encapsulates the underlying camel machinery. ++ * ++ */ ++trait Camel extends ConsumerRegistry with ProducerRegistry with Extension with Activation { ++ /** ++ * Underlying camel context. ++ * ++ * It can be used to configure camel manually, i.e. when the user wants to add new routes or endpoints, ++ * i.e.

camel.context.addRoutes(...)
++ * ++ * @see [[org.apache.camel.CamelContext]] ++ */ ++ def context: CamelContext ++ ++ /** ++ * Producer template. ++ * @see [[org.apache.camel.ProducerTemplate]] ++ */ ++ def template: ProducerTemplate ++ ++ /** ++ * Associated `ActorSystem`. ++ * ++ *

It can be used to start producers, consumers or any other actors which need to interact with camel, ++ * for example: ++ * {{{ ++ * val system = ActorSystem(""test"") ++ * system.actorOf(Props[SysOutConsumer])","removed def system from Camel trait, it is not needed in the end for the user. (you can always get to the system using the normal routes) Added a comment that Camel is shutdown when the associated ActorSystem that uses a Camel extension is shut down. +",f74616f828d3e31724d768dd86ce05af85d97ade +506662,2,"Because I'm stupid. Fixed. """,2012-03-01 02:27:24,jboner,akka,akka,,https://github.com/akka/akka-core/pull/329#discussion_r506662,2012-03-01T13:27:24Z,2012-03-12T18:22:16Z,jboner,CONTRIBUTOR,akka-cluster/src/main/scala/akka/cluster/Node.scala,,,,,1,"@@ -0,0 +1,803 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++ ++package akka.cluster ++ ++import akka.actor._ ++import akka.actor.Status._ ++import akka.remote._ ++import akka.routing._ ++import akka.event.Logging ++import akka.dispatch.Await ++import akka.pattern.ask ++import akka.util._ ++import akka.config.ConfigurationException ++ ++import java.util.concurrent.atomic.{ AtomicReference, AtomicBoolean } ++import java.util.concurrent.TimeUnit._ ++import java.util.concurrent.TimeoutException ++import java.security.SecureRandom ++ ++import scala.collection.immutable.{ Map, SortedSet } ++import scala.annotation.tailrec ++ ++import com.google.protobuf.ByteString ++ ++/** ++ * Interface for membership change listener. ++ */ ++trait MembershipChangeListener { ++ def notify(members: SortedSet[Member]): Unit ++} ++ ++/** ++ * Interface for meta data change listener. ++ */ ++trait MetaDataChangeListener { // FIXME add management and notification for MetaDataChangeListener ++ def notify(meta: Map[String, Array[Byte]]): Unit ++} ++ ++// FIXME create Protobuf messages out of all the Gossip stuff - but wait until the prototol is fully stablized. ++ ++/** ++ * Base trait for all cluster messages. All ClusterMessage's are serializable. ++ */ ++sealed trait ClusterMessage extends Serializable ++ ++/** ++ * Cluster commands sent by the USER. ++ */ ++object ClusterAction { ++ ++ /** ++ * Command to join the cluster. Sent when a node (reprsesented by 'address') ++ * wants to join another node (the receiver). ++ */ ++ case class Join(address: Address) extends ClusterMessage ++ ++ /** ++ * Command to set a node to Up (from Joining). ++ */ ++ case object Up extends ClusterMessage ++ ++ /** ++ * Command to leave the cluster. ++ */ ++ case object Leave extends ClusterMessage ++ ++ /** ++ * Command to mark node as temporary down. ++ */ ++ case object Down extends ClusterMessage ++ ++ /** ++ * Command to mark a node to be removed from the cluster immediately. ++ */ ++ case object Exit extends ClusterMessage ++ ++ /** ++ * Command to remove a node from the cluster immediately. ++ */ ++ case object Remove extends ClusterMessage ++} ++ ++/** ++ * Represents the address and the current status of a cluster member node. ++ */ ++case class Member(address: Address, status: MemberStatus) extends ClusterMessage ++ ++/** ++ * Envelope adding a sender address to the gossip. ++ */ ++case class GossipEnvelope(sender: Member, gossip: Gossip) extends ClusterMessage ++ ++/** ++ * Defines the current status of a cluster member node ++ * ++ * Can be one of: Joining, Up, Leaving, Exiting and Down. ++ */ ++sealed trait MemberStatus extends ClusterMessage ++object MemberStatus { ++ case object Joining extends MemberStatus ++ case object Up extends MemberStatus ++ case object Leaving extends MemberStatus ++ case object Exiting extends MemberStatus ++ case object Down extends MemberStatus ++ case object Removed extends MemberStatus ++} ++ ++// sealed trait PartitioningStatus ++// object PartitioningStatus { ++// case object Complete extends PartitioningStatus ++// case object Awaiting extends PartitioningStatus ++// } ++ ++// case class PartitioningChange( ++// from: Address, ++// to: Address, ++// path: PartitionPath, ++// status: PartitioningStatus) ++ ++/** ++ * Represents the overview of the cluster, holds the cluster convergence table and set with unreachable nodes. ++ */ ++case class GossipOverview( ++ seen: Map[Address, VectorClock] = Map.empty[Address, VectorClock], ++ unreachable: Set[Address] = Set.empty[Address]) { ++ ++ override def toString = ++ ""GossipOverview(seen = ["" + seen.mkString("", "") + ++ ""], unreachable = ["" + unreachable.mkString("", "") + ++ ""])"" ++} ++ ++/** ++ * Represents the state of the cluster; cluster ring membership, ring convergence, meta data - all versioned by a vector clock. ++ */ ++case class Gossip( ++ overview: GossipOverview = GossipOverview(), ++ members: SortedSet[Member], // sorted set of members with their status, sorted by name ++ //partitions: Tree[PartitionPath, Node] = Tree.empty[PartitionPath, Node], // name/partition service ++ //pending: Set[PartitioningChange] = Set.empty[PartitioningChange], ++ meta: Map[String, Array[Byte]] = Map.empty[String, Array[Byte]], ++ version: VectorClock = VectorClock()) // vector clock version ++ extends ClusterMessage // is a serializable cluster message ++ with Versioned[Gossip] { ++ ++ /** ++ * Increments the version for this 'Node'. ++ */ ++ def +(node: VectorClock.Node): Gossip = copy(version = version + node) ++ ++ def +(member: Member): Gossip = { ++ if (members contains member) this ++ else this copy (members = members + member) ++ } ++ ++ /** ++ * Marks the gossip as seen by this node (remoteAddress) by updating the address entry in the 'gossip.overview.seen' ++ * Map with the VectorClock for the new gossip. ++ */ ++ def seen(address: Address): Gossip = ++ this copy (overview = overview copy (seen = overview.seen + (address -> version))) ++ ++ override def toString = ++ ""Gossip("" + ++ ""overview = "" + overview + ++ "", members = ["" + members.mkString("", "") + ++ ""], meta = ["" + meta.mkString("", "") + ++ ""], version = "" + version + ++ "")"" ++} ++ ++/** ++ * FSM actor managing the different cluster nodes states. ++ * Single instance - e.g. serialized access to Node - message after message. ++ */ ++final class ClusterCommandDaemon(system: ActorSystem, node: Node) extends Actor with FSM[MemberStatus, Unit] { ++ ++ // start in JOINING ++ startWith(MemberStatus.Joining, Unit) ++ ++ // ======================== ++ // === IN JOINING === ++ when(MemberStatus.Joining) { ++ case Event(ClusterAction.Up, _) ⇒ ++ node.up() ++ goto(MemberStatus.Up) ++ } ++ ++ // ======================== ++ // === IN UP === ++ when(MemberStatus.Up) { ++ case Event(ClusterAction.Down, _) ⇒ ++ node.downing() ++ goto(MemberStatus.Down) ++ ++ case Event(ClusterAction.Leave, _) ⇒ ++ node.leaving() ++ goto(MemberStatus.Leaving) ++ ++ case Event(ClusterAction.Exit, _) ⇒ ++ node.exiting() ++ goto(MemberStatus.Exiting) ++ ++ case Event(ClusterAction.Remove, _) ⇒ ++ node.removing() ++ goto(MemberStatus.Removed) ++ } ++ ++ // ======================== ++ // === IN LEAVING === ++ when(MemberStatus.Leaving) { ++ case Event(ClusterAction.Down, _) ⇒ ++ node.downing() ++ goto(MemberStatus.Down) ++ ++ case Event(ClusterAction.Remove, _) ⇒ ++ node.removing() ++ goto(MemberStatus.Removed) ++ } ++ ++ // ======================== ++ // === IN EXITING === ++ when(MemberStatus.Exiting) { ++ case Event(ClusterAction.Remove, _) ⇒ ++ node.removing() ++ goto(MemberStatus.Removed) ++ } ++ ++ // ======================== ++ // === IN DOWN === ++ when(MemberStatus.Down) { ++ // FIXME How to transition from DOWN => JOINING when node comes back online. Can't just listen to Gossip message since it is received be another actor. How to fix this? ++ case Event(ClusterAction.Remove, _) ⇒ ++ node.removing() ++ goto(MemberStatus.Removed) ++ } ++ ++ // ======================== ++ // === IN REMOVED === ++ when(MemberStatus.Removed) { ++ case command ⇒ ++ log.warning(""Removed node [{}] received cluster command [{}]"", system.name, command) ++ stay ++ } ++ ++ // ======================== ++ // === GENERIC AND UNHANDLED COMMANDS === ++ whenUnhandled { ++ // should be able to handle Join in any state ++ case Event(ClusterAction.Join(address), _) ⇒ ++ node.joining(address) ++ stay ++ ++ case Event(command, _) ⇒ { ++ log.warning(""Unhandled command [{}] in state [{}]"", command, stateName) ++ stay ++ } ++ } ++} ++ ++/** ++ * Pooled and routed wit N number of configurable instances. ++ * Concurrent access to Node. ++ */ ++final class ClusterGossipDaemon(system: ActorSystem, node: Node) extends Actor { ++ val log = Logging(system, ""ClusterGossipDaemon"") ++ ++ def receive = { ++ case GossipEnvelope(sender, gossip) ⇒ node.receive(sender, gossip) ++ case unknown ⇒ log.error(""Unknown message sent to cluster daemon ["" + unknown + ""]"") ++ } ++} ++ ++/** ++ * Node Extension Id and factory for creating Node extension. ++ * Example: ++ * {{{ ++ * val node = NodeExtension(system) ++ * ++ * if (node.isLeader) { ... } ++ * }}} ++ * ++ * Example: ++ * {{{ ++ * import akka.cluster._ ++ * ++ * val node = system.node // implicit conversion adds 'node' method ++ * ++ * if (node.isLeader) { ... } ++ * }}} ++ */ ++object NodeExtension extends ExtensionId[Node] with ExtensionIdProvider { ++ override def get(system: ActorSystem): Node = super.get(system) ++ ++ override def lookup = NodeExtension ++ ++ override def createExtension(system: ExtendedActorSystem): Node = new Node(system.asInstanceOf[ActorSystemImpl]) // not nice but need API in ActorSystemImpl inside Node ++} ++ ++/** ++ * This module is responsible for Gossiping cluster information. The abstraction maintains the list of live ++ * and dead members. Periodically i.e. every 1 second this module chooses a random member and initiates a round ++ * of Gossip with it. Whenever it gets gossip updates it updates the Failure Detector with the liveness ++ * information. ++ *

++ * During each of these runs the member initiates gossip exchange according to following rules (as defined in the ++ * Cassandra documentation [http://wiki.apache.org/cassandra/ArchitectureGossip]: ++ *

++ *   1) Gossip to random live member (if any)
++ *   2) Gossip to random unreachable member with certain probability depending on number of unreachable and live members
++ *   3) If the member gossiped to at (1) was not deputy, or the number of live members is less than number of deputy list,
++ *       gossip to random deputy with certain probability depending on number of unreachable, deputy and live members.
++ * 
++ * ++ * Example: ++ * {{{ ++ * val node = NodeExtension(system) ++ * ++ * if (node.isLeader) { ... } ++ * }}} ++ * ++ * Example: ++ * {{{ ++ * import akka.cluster._ ++ * ++ * val node = system.node // implicit conversion adds 'node' method ++ * ++ * if (node.isLeader) { ... } ++ * }}} ++ */ ++class Node(system: ActorSystemImpl) extends Extension { ++ ++ /** ++ * Represents the state for this Node. Implemented using optimistic lockless concurrency, ++ * all state is represented by this immutable case class and managed by an AtomicReference. ++ */ ++ private case class State( ++ self: Member, ++ latestGossip: Gossip, ++ memberMembershipChangeListeners: Set[MembershipChangeListener] = Set.empty[MembershipChangeListener]) ++ ++ if (!system.provider.isInstanceOf[RemoteActorRefProvider]) ++ throw new ConfigurationException(""ActorSystem["" + system + ""] needs to have a 'RemoteActorRefProvider' enabled in the configuration"") ++ ++ private val remote: RemoteActorRefProvider = system.provider.asInstanceOf[RemoteActorRefProvider] ++ ++ private val remoteSettings = new RemoteSettings(system.settings.config, system.name) ++ private val clusterSettings = new ClusterSettings(system.settings.config, system.name) ++ ++ private val remoteAddress = remote.transport.address ++ private val vclockNode = VectorClock.Node(remoteAddress.toString) ++ ++ private val gossipInitialDelay = clusterSettings.GossipInitialDelay ++ private val gossipFrequency = clusterSettings.GossipFrequency ++ ++ implicit private val memberOrdering = Ordering.fromLessThan[Member](_.address.toString < _.address.toString) ++ ++ implicit private val defaultTimeout = Timeout(remoteSettings.RemoteSystemDaemonAckTimeout) ++ ++ val failureDetector = new AccrualFailureDetector( ++ system, remoteAddress, clusterSettings.FailureDetectorThreshold, clusterSettings.FailureDetectorMaxSampleSize) ++ ++ private val nrOfDeputyNodes = clusterSettings.NrOfDeputyNodes ++ private val nrOfGossipDaemons = clusterSettings.NrOfGossipDaemons ++ private val nodeToJoin: Option[Address] = clusterSettings.NodeToJoin filter (_ != remoteAddress) ++ ++ private val serialization = remote.serialization ++ ++ private val isRunning = new AtomicBoolean(true) ++ private val log = Logging(system, ""Node"") ++ private val random = SecureRandom.getInstance(""SHA1PRNG"") ++ ++ private val clusterCommandDaemon = system.systemActorOf( ++ Props(new ClusterCommandDaemon(system, this)), ""clusterCommand"") ++ ++ private val clusterGossipDaemon = system.systemActorOf( ++ Props(new ClusterGossipDaemon(system, this)).withRouter(RoundRobinRouter(nrOfGossipDaemons)), ""clusterGossip"") ++ ++ private val state = { ++ val member = Member(remoteAddress, MemberStatus.Joining) ++ val gossip = Gossip(members = SortedSet.empty[Member] + member) + vclockNode // add me as member and update my vector clock ++ new AtomicReference[State](State(member, gossip)) ++ } ++ ++ import Versioned.latestVersionOf ++ ++ log.info(""Node [{}] - Starting cluster Node..."", remoteAddress) ++ ++ // try to join the node defined in the 'akka.cluster.node-to-join' option ++ autoJoin() ++ ++ // start periodic gossip to random nodes in cluster ++ private val gossipCanceller = system.scheduler.schedule(gossipInitialDelay, gossipFrequency) { ++ gossip() ++ } ++ ++ // start periodic cluster scrutinization (moving nodes condemned by the failure detector to unreachable list) ++ private val scrutinizeCanceller = system.scheduler.schedule(gossipInitialDelay, gossipFrequency) { ++ scrutinize() ++ } ++ ++ // ====================================================== ++ // ===================== PUBLIC API ===================== ++ // ====================================================== ++ ++ /** ++ * Latest gossip. ++ */ ++ def latestGossip: Gossip = state.get.latestGossip ++ ++ /** ++ * Member status for this node. ++ */ ++ def self: Member = state.get.self ++ ++ /** ++ * Is this node the leader? ++ */ ++ def isLeader: Boolean = { ++ val currentState = state.get ++ remoteAddress == currentState.latestGossip.members.head.address ++ } ++ ++ /** ++ * Is this node a singleton cluster? ++ */ ++ def isSingletonCluster: Boolean = isSingletonCluster(state.get) ++ ++ /** ++ * Checks if we have a cluster convergence. ++ * ++ * @returns Some(convergedGossip) if convergence have been reached and None if not ++ */ ++ def convergence: Option[Gossip] = convergence(latestGossip) ++ ++ /** ++ * Shuts down all connections to other members, the cluster daemon and the periodic gossip and cleanup tasks. ++ */ ++ def shutdown() { ++ ++ // FIXME Cheating for now. Can't just shut down. Node must first gossip an Leave command, wait for Leader to do proper Handoff and then await an Exit command before switching to Removed ++ ++ if (isRunning.compareAndSet(true, false)) { ++ log.info(""Node [{}] - Shutting down Node and ClusterDaemon..."", remoteAddress) ++ ++ try system.stop(clusterCommandDaemon) finally { ++ try system.stop(clusterGossipDaemon) finally { ++ try gossipCanceller.cancel() finally { ++ try scrutinizeCanceller.cancel() finally { ++ log.info(""Node [{}] - Node and ClusterDaemon shut down successfully"", remoteAddress) ++ } ++ } ++ } ++ } ++ } ++ } ++ ++ /** ++ * Registers a listener to subscribe to cluster membership changes. ++ */ ++ @tailrec ++ final def registerListener(listener: MembershipChangeListener) { ++ val localState = state.get ++ val newListeners = localState.memberMembershipChangeListeners + listener ++ val newState = localState copy (memberMembershipChangeListeners = newListeners) ++ if (!state.compareAndSet(localState, newState)) registerListener(listener) // recur ++ } ++ ++ /** ++ * Unsubscribes to cluster membership changes. ++ */ ++ @tailrec ++ final def unregisterListener(listener: MembershipChangeListener) { ++ val localState = state.get ++ val newListeners = localState.memberMembershipChangeListeners - listener ++ val newState = localState copy (memberMembershipChangeListeners = newListeners) ++ if (!state.compareAndSet(localState, newState)) unregisterListener(listener) // recur ++ } ++ ++ /** ++ * Send command to JOIN one node to another. ++ */ ++ def sendJoin(address: Address) { ++ clusterCommandDaemon ! ClusterAction.Join(address) ++ } ++ ++ /** ++ * Send command to issue state transition to LEAVING. ++ */ ++ def sendLeave() { ++ clusterCommandDaemon ! ClusterAction.Leave ++ } ++ ++ /** ++ * Send command to issue state transition to EXITING. ++ */ ++ def sendDown() { ++ clusterCommandDaemon ! ClusterAction.Down ++ } ++ ++ /** ++ * Send command to issue state transition to REMOVED. ++ */ ++ def sendRemove() { ++ clusterCommandDaemon ! ClusterAction.Remove ++ } ++ ++ // ======================================================== ++ // ===================== INTERNAL API ===================== ++ // ======================================================== ++ ++ /** ++ * State transition to JOINING. ++ * New node joining. ++ */ ++ @tailrec ++ private[cluster] final def joining(node: Address) { ++ log.info(""Node [{}] - Node [{}] is joining"", remoteAddress, node) ++ ++ failureDetector heartbeat node // update heartbeat in failure detector ++ ++ val localState = state.get ++ val localGossip = localState.latestGossip ++ val localMembers = localGossip.members ++ ++ val newMembers = localMembers + Member(node, MemberStatus.Joining) // add joining node as Joining ++ val newGossip = localGossip copy (members = newMembers) ++ ++ val versionedGossip = newGossip + vclockNode ++ val seenVersionedGossip = versionedGossip seen remoteAddress ++ ++ val newState = localState copy (latestGossip = seenVersionedGossip) ++ ++ if (!state.compareAndSet(localState, newState)) joining(node) // recur if we failed update ++ else { ++ if (convergence(newState.latestGossip).isDefined) { ++ newState.memberMembershipChangeListeners map { _ notify newMembers }","Because I'm stupid. Fixed. +",cf3fa9fa3ce9e9312db0922370c93ce1af9db7c8 +405333,0,"Is this test run automatically? In that case why do we have so many spec wrappers for other junit tests?""",2012-01-31 19:51:32,patriknw,akka,akka,,https://github.com/akka/akka-core/pull/286#discussion_r405333,2012-02-01T06:51:32Z,2012-02-01T06:51:32Z,patriknw,CONTRIBUTOR,akka-testkit/src/test/java/akka/testkit/TestActorRefJavaSpec.java,,12.0,,,12,"@@ -0,0 +1,19 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++ ++package akka.testkit; ++ ++import org.junit.Test; ++import akka.actor.Props; ++ ++import static org.junit.Assert.*; ++ ++public class TestActorRefJavaSpec {","Is this test run automatically? In that case why do we have so many spec wrappers for other junit tests? +",dcebd1deb209d953912976f2183893ab88a8f593 +392986,0,"I don’t know, I just copied your code into a new file …""",2012-01-27 07:46:20,rkuhn,akka,akka,,https://github.com/akka/akka-core/pull/275#discussion_r392986,2012-01-27T18:46:20Z,2012-01-30T10:58:22Z,rkuhn,CONTRIBUTOR,akka-remote/src/main/scala/akka/remote/netty/Client.scala,,196.0,,,196,"@@ -0,0 +1,346 @@ ++/** ++ * Copyright (C) 2009-2011 Typesafe Inc. ++ */ ++package akka.remote.netty ++ ++import java.net.InetSocketAddress ++import org.jboss.netty.util.HashedWheelTimer ++import org.jboss.netty.bootstrap.ClientBootstrap ++import org.jboss.netty.channel.group.DefaultChannelGroup ++import org.jboss.netty.channel.{ ChannelHandler, StaticChannelPipeline, SimpleChannelUpstreamHandler, MessageEvent, ExceptionEvent, ChannelStateEvent, ChannelPipelineFactory, ChannelPipeline, ChannelHandlerContext, ChannelFuture, Channel } ++import org.jboss.netty.handler.codec.frame.{ LengthFieldPrepender, LengthFieldBasedFrameDecoder } ++import org.jboss.netty.handler.execution.ExecutionHandler ++import org.jboss.netty.handler.timeout.{ ReadTimeoutHandler, ReadTimeoutException } ++import akka.remote.RemoteProtocol.{ RemoteControlProtocol, CommandType, AkkaRemoteProtocol } ++import akka.remote.{ RemoteProtocol, RemoteMessage, RemoteLifeCycleEvent, RemoteClientStarted, RemoteClientShutdown, RemoteClientException, RemoteClientError, RemoteClientDisconnected, RemoteClientConnected } ++import akka.actor.{ simpleName, Address } ++import akka.AkkaException ++import akka.event.Logging ++import akka.util.Switch ++import akka.actor.ActorRef ++import org.jboss.netty.channel.ChannelFutureListener ++import akka.remote.RemoteClientWriteFailed ++import java.net.InetAddress ++import org.jboss.netty.util.TimerTask ++import org.jboss.netty.util.Timeout ++import java.util.concurrent.TimeUnit ++ ++class RemoteClientMessageBufferException(message: String, cause: Throwable) extends AkkaException(message, cause) { ++ def this(msg: String) = this(msg, null) ++} ++ ++/** ++ * This is the abstract baseclass for netty remote clients, currently there's only an ++ * ActiveRemoteClient, but others could be feasible, like a PassiveRemoteClient that ++ * reuses an already established connection. ++ */ ++abstract class RemoteClient private[akka] ( ++ val netty: NettyRemoteTransport, ++ val remoteAddress: Address) { ++ ++ val log = Logging(netty.system, ""RemoteClient"") ++ ++ val name = simpleName(this) + ""@"" + remoteAddress ++ ++ private[remote] val runSwitch = new Switch() ++ ++ private[remote] def isRunning = runSwitch.isOn ++ ++ protected def currentChannel: Channel ++ ++ def connect(reconnectIfAlreadyConnected: Boolean = false): Boolean ++ ++ def shutdown(): Boolean ++ ++ def isBoundTo(address: Address): Boolean = remoteAddress == address ++ ++ /** ++ * Converts the message to the wireprotocol and sends the message across the wire ++ */ ++ def send(message: Any, senderOption: Option[ActorRef], recipient: ActorRef): Unit = if (isRunning) { ++ if (netty.remoteSettings.LogSend) log.debug(""Sending message {} from {} to {}"", message, senderOption, recipient) ++ send((message, senderOption, recipient)) ++ } else { ++ val exception = new RemoteClientException(""RemoteModule client is not running, make sure you have invoked 'RemoteClient.connect()' before using it."", netty, remoteAddress) ++ netty.notifyListeners(RemoteClientError(exception, netty, remoteAddress)) ++ throw exception ++ } ++ ++ /** ++ * Sends the message across the wire ++ */ ++ private def send(request: (Any, Option[ActorRef], ActorRef)): Unit = { ++ try { ++ val channel = currentChannel ++ val f = channel.write(request) ++ f.addListener( ++ new ChannelFutureListener { ++ def operationComplete(future: ChannelFuture) { ++ if (future.isCancelled || !future.isSuccess) { ++ netty.notifyListeners(RemoteClientWriteFailed(request, future.getCause, netty, remoteAddress)) ++ } ++ } ++ }) ++ // Check if we should back off ++ if (!channel.isWritable) { ++ val backoff = netty.settings.BackoffTimeout ++ if (backoff.length > 0 && !f.await(backoff.length, backoff.unit)) f.cancel() //Waited as long as we could, now back off ++ } ++ } catch { ++ case e: Exception ⇒ netty.notifyListeners(RemoteClientError(e, netty, remoteAddress)) ++ } ++ } ++ ++ override def toString = name ++} ++ ++/** ++ * RemoteClient represents a connection to an Akka node. Is used to send messages to remote actors on the node. ++ */ ++class ActiveRemoteClient private[akka] ( ++ netty: NettyRemoteTransport, ++ remoteAddress: Address, ++ localAddress: Address) ++ extends RemoteClient(netty, remoteAddress) { ++ ++ import netty.settings ++ ++ //TODO rewrite to a wrapper object (minimize volatile access and maximize encapsulation) ++ @volatile ++ private var bootstrap: ClientBootstrap = _ ++ @volatile ++ private var connection: ChannelFuture = _ ++ @volatile ++ private[remote] var openChannels: DefaultChannelGroup = _ ++ @volatile ++ private var executionHandler: ExecutionHandler = _ ++ ++ @volatile ++ private var reconnectionTimeWindowStart = 0L ++ ++ def notifyListeners(msg: RemoteLifeCycleEvent): Unit = netty.notifyListeners(msg) ++ ++ def currentChannel = connection.getChannel ++ ++ /** ++ * Connect to remote server. ++ */ ++ def connect(reconnectIfAlreadyConnected: Boolean = false): Boolean = { ++ ++ def sendSecureCookie(connection: ChannelFuture) { ++ val handshake = RemoteControlProtocol.newBuilder.setCommandType(CommandType.CONNECT) ++ if (settings.SecureCookie.nonEmpty) handshake.setCookie(settings.SecureCookie.get) ++ handshake.setOrigin(RemoteProtocol.AddressProtocol.newBuilder ++ .setSystem(localAddress.system) ++ .setHostname(localAddress.host.get) ++ .setPort(localAddress.port.get) ++ .build) ++ connection.getChannel.write(netty.createControlEnvelope(handshake.build)) ++ } ++ ++ def attemptReconnect(): Boolean = { ++ val remoteIP = InetAddress.getByName(remoteAddress.host.get) ++ log.debug(""Remote client reconnecting to [{}|{}]"", remoteAddress, remoteIP) ++ connection = bootstrap.connect(new InetSocketAddress(remoteIP, remoteAddress.port.get)) ++ openChannels.add(connection.awaitUninterruptibly.getChannel) // Wait until the connection attempt succeeds or fails. ++ ++ if (!connection.isSuccess) { ++ notifyListeners(RemoteClientError(connection.getCause, netty, remoteAddress)) ++ false ++ } else { ++ sendSecureCookie(connection) ++ true ++ } ++ } ++ ++ runSwitch switchOn { ++ openChannels = new DefaultDisposableChannelGroup(classOf[RemoteClient].getName) ++ ++ executionHandler = new ExecutionHandler(netty.executor) ++ ++ bootstrap = new ClientBootstrap(netty.clientChannelFactory) ++ bootstrap.setPipelineFactory(new ActiveRemoteClientPipelineFactory(name, bootstrap, executionHandler, remoteAddress, this)) ++ bootstrap.setOption(""tcpNoDelay"", true) ++ bootstrap.setOption(""keepAlive"", true) ++ bootstrap.setOption(""connectTimeoutMillis"", settings.ConnectionTimeout.toMillis) ++ ++ val remoteIP = InetAddress.getByName(remoteAddress.host.get) ++ log.debug(""Starting remote client connection to [{}|{}]"", remoteAddress, remoteIP) ++ ++ connection = bootstrap.connect(new InetSocketAddress(remoteIP, remoteAddress.port.get)) ++ ++ openChannels.add(connection.awaitUninterruptibly.getChannel) // Wait until the connection attempt succeeds or fails. ++ ++ if (!connection.isSuccess) { ++ notifyListeners(RemoteClientError(connection.getCause, netty, remoteAddress)) ++ false ++ } else { ++ sendSecureCookie(connection) ++ notifyListeners(RemoteClientStarted(netty, remoteAddress)) ++ true ++ } ++ } match { ++ case true ⇒ true ++ case false if reconnectIfAlreadyConnected ⇒ ++ connection.getChannel.close() ++ openChannels.remove(connection.getChannel) ++ ++ log.debug(""Remote client reconnecting to [{}]"", remoteAddress) ++ attemptReconnect() ++ ++ case false ⇒ false ++ } ++ } ++ ++ // Please note that this method does _not_ remove the ARC from the NettyRemoteClientModule's map of clients","I don’t know, I just copied your code into a new file … +",4fb0858e557232e5f4a7e5b364d1697c0e21bdd1 +316230,0,"use: new Props(JAdvancedCalculatorActor.class)""",2011-12-27 11:21:33,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/194#discussion_r316230,2011-12-27T22:21:33Z,2011-12-28T00:41:32Z,viktorklang,CONTRIBUTOR,akka-samples/akka-sample-remote/src/main/java/sample/remote/calculator/java/JCreationApplication.java,,,,,1,"@@ -0,0 +1,35 @@ ++/** ++ * Copyright (C) 2009-2011 Typesafe Inc. ++ */ ++package sample.remote.calculator.java; ++ ++import akka.actor.ActorRef; ++import akka.actor.ActorSystem; ++import akka.actor.Props; ++import akka.kernel.Bootable; ++import com.typesafe.config.ConfigFactory; ++ ++public class JCreationApplication implements Bootable { ++ private ActorSystem system; ++ private ActorRef actor; ++ private ActorRef remoteActor; ++ ++ public JCreationApplication() { ++ system = ActorSystem.create(""CreationApplication"", ConfigFactory.load().getConfig(""remotecreation"")); ++ actor = system.actorOf(new Props().withCreator(JCreationActor.class)); ++ remoteActor = system.actorOf(new Props().withCreator(JAdvancedCalculatorActor.class), ""advancedCalculator"");","use: + +``` +new Props(JAdvancedCalculatorActor.class) +``` +",f21651d7479c5572b0339a02c0b1ce24cdc167da +309221,0,"On Wed, Dec 21, 2011 at 5:08 PM, viktorklang < reply@reply.github.com > wrote: > > > > // FIXME: Dispatchers registered here are are not removed, see ticket > #1494 > > - private val dispatchers = new ConcurrentHashMap[String, > MessageDispatcher] > """,2011-12-21 05:23:23,patriknw,akka,akka,,https://github.com/akka/akka-core/pull/182#discussion_r309221,2011-12-21T16:23:23Z,2011-12-21T22:47:22Z,patriknw,CONTRIBUTOR,akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala,,65.0,,,1,"@@ -67,15 +68,18 @@ class Dispatchers(val settings: ActorSystem.Settings, val prerequisites: Dispatc + if (settings.MailboxCapacity < 1) UnboundedMailbox() + else BoundedMailbox(settings.MailboxCapacity, settings.MailboxPushTimeout) + +- val defaultDispatcherConfig = settings.config.getConfig(""akka.actor.default-dispatcher"") ++ val defaultDispatcherConfig = { ++ val key = ""akka.actor.default-dispatcher"" ++ keyConfig(key).withFallback(settings.config.getConfig(key)) ++ } + +- lazy val defaultGlobalDispatcher: MessageDispatcher = +- from(defaultDispatcherConfig) getOrElse { +- throw new ConfigurationException(""Wrong configuration [akka.actor.default-dispatcher]"") +- } ++ private lazy val defaultDispatcherConfigurator: MessageDispatcherConfigurator = ++ configuratorFrom(defaultDispatcherConfig) ++ ++ lazy val defaultGlobalDispatcher: MessageDispatcher = defaultDispatcherConfigurator.dispatcher() + + // FIXME: Dispatchers registered here are are not removed, see ticket #1494 +- private val dispatchers = new ConcurrentHashMap[String, MessageDispatcher] ++ private val dispatcherConfigurators = new ConcurrentHashMap[String, MessageDispatcherConfigurator] + + /** + * Returns a dispatcher as specified in configuration, or if not defined it uses","On Wed, Dec 21, 2011 at 5:08 PM, viktorklang < +reply@reply.github.com + +> wrote: +> +> > // FIXME: Dispatchers registered here are are not removed, see ticket +> > #1494 +> > - private val dispatchers = new ConcurrentHashMap[String, +> > MessageDispatcher] +> > - private val dispatcherConfigurators = new ConcurrentHashMap[String, +> > MessageDispatcherConfigurator] +> > +> > /** +> > - Returns a dispatcher as specified in configuration, or if not +> > defined it uses +> +> Could be a source of hard to diagnose problems if it just silently uses +> the default. Perhaps log a warning +> +> That's why I log a Debug, but I can change it to Info. Don't think it's a +> Warning, because I think as a start default-dispatcher is a good default, +> but still with possibility to tune a specific dispatcher, if needed. +> +> --- +> +> Reply to this email directly or view it on GitHub: +> https://github.com/jboner/akka/pull/182/files#r309168 + +## + +Patrik Nordwall +Typesafe http://typesafe.com/ - Enterprise-Grade Scala from the Experts +Twitter: @patriknw +",ed2fb14dcf0120a6c126fe9c99038d897dbcdf0d +296660,0,"I'm curious as to why the signature of ? still includes a timeout. Since it returns a Future, which will no longer time out, isn't the timeout superfluous?""",2011-12-15 04:12:55,nuttycom,akka,akka,,https://github.com/akka/akka-core/pull/147#discussion_r296660,2011-12-15T15:12:55Z,2011-12-15T15:54:48Z,nuttycom,NONE,akka-actor/src/main/scala/akka/actor/ActorRef.scala,,450.0,,,58,"@@ -455,11 +448,13 @@ class AskActorRef( + } + + override def ?(message: Any)(implicit timeout: Timeout): Future[Any] =","I'm curious as to why the signature of ? still includes a timeout. Since it returns a Future, which will no longer time out, isn't the timeout superfluous? +",0af92f24400f1b05d1919be54dfd822037f0076f +284725,0,"final class?""",2011-12-10 01:01:32,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/144#discussion_r284725,2011-12-10T12:01:32Z,2011-12-13T15:06:05Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorRef.scala,,412.0,,,107,"@@ -403,6 +404,41 @@ class DeadLetterActorRef(val eventStream: EventStream) extends MinimalActorRef { + private def writeReplace(): AnyRef = DeadLetterActorRef.serialized + } + ++class VirtualPathContainer(val path: ActorPath, override val getParent: InternalActorRef, val log: LoggingAdapter) extends MinimalActorRef {","final class? +",134fac4bfe8d6f8b4e9b96dfbfdf532d48ae3c86 +269682,2,"Damn clean, Mr Kuhn, damn clean!""",2011-12-05 01:54:55,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/119#discussion_r269682,2011-12-05T12:54:55Z,2011-12-05T21:48:28Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorRef.scala,,159.0,,,98,"@@ -118,14 +111,76 @@ abstract class ActorRef extends java.lang.Comparable[ActorRef] with Serializable + */ + def isTerminated: Boolean + +- override def hashCode: Int = HashCode.hash(HashCode.SEED, address) ++ // FIXME RK check if we should scramble the bits or whether they can stay the same ++ override def hashCode: Int = path.hashCode + +- override def equals(that: Any): Boolean = { +- that.isInstanceOf[ActorRef] && +- that.asInstanceOf[ActorRef].address == address ++ override def equals(that: Any): Boolean = that match { ++ case other: ActorRef ⇒ path == other.path ++ case _ ⇒ false + } + +- override def toString = ""Actor[%s]"".format(address) ++ override def toString = ""Actor[%s]"".format(path) ++} ++ ++/** ++ * This trait represents the Scala Actor API ++ * There are implicit conversions in ../actor/Implicits.scala ++ * from ActorRef -> ScalaActorRef and back ++ */ ++trait ScalaActorRef { ref: ActorRef ⇒ ++ ++ /** ++ * Sends a one-way asynchronous message. E.g. fire-and-forget semantics. ++ *

++ * ++ * If invoked from within an actor then the actor reference is implicitly passed on as the implicit 'sender' argument. ++ *

++ * ++ * This actor 'sender' reference is then available in the receiving actor in the 'sender' member variable, ++ * if invoked from within an Actor. If not then no sender is available. ++ *

++   *   actor ! message
++   * 
++ *

++ */ ++ def !(message: Any)(implicit sender: ActorRef = null): Unit ++ ++ /** ++ * Sends a message asynchronously, returning a future which may eventually hold the reply. ++ */ ++ def ?(message: Any)(implicit timeout: Timeout): Future[Any] ++ ++ /** ++ * Sends a message asynchronously, returning a future which may eventually hold the reply. ++ * The implicit parameter with the default value is just there to disambiguate it from the version that takes the ++ * implicit timeout ++ */ ++ def ?(message: Any, timeout: Timeout)(implicit ignore: Int = 0): Future[Any] = ?(message)(timeout) ++}","Damn clean, Mr Kuhn, damn clean! +",9d7597c7282711889d74bd9b4d7bdae5ea254104 +269792,2,"These two are :(""",2011-12-05 03:22:21,viktorklang,akka,akka,,https://github.com/akka/akka-core/pull/119#discussion_r269792,2011-12-05T14:22:21Z,2011-12-05T21:48:29Z,viktorklang,CONTRIBUTOR,akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala,,313.0,,,318,"@@ -106,57 +133,183 @@ trait ActorRefFactory { + /** + * Father of all children created by this interface. + */ +- protected def guardian: ActorRef ++ protected def guardian: InternalActorRef ++ ++ protected def lookupRoot: InternalActorRef + + protected def randomName(): String + ++ /** ++ * Create new actor as child of this context and give it an automatically ++ * generated name (currently similar to base64-encoded integer count, ++ * reversed and with “$” prepended, may change in the future). ++ * ++ * See [[akka.actor.Props]] for details on how to obtain a `Props` object. ++ */ + def actorOf(props: Props): ActorRef = provider.actorOf(systemImpl, props, guardian, randomName(), false) + +- /* +- * TODO this will have to go at some point, because creating two actors with +- * the same address can race on the cluster, and then you never know which +- * implementation wins ++ /** ++ * Create new actor as child of this context with the given name, which must ++ * not be null, empty or start with “$”. If the given name is already in use, ++ * and `InvalidActorNameException` is thrown. ++ * ++ * See [[akka.actor.Props]] for details on how to obtain a `Props` object. + */ +- def actorOf(props: Props, name: String): ActorRef = { +- if (name == null || name == """" || name.startsWith(""$"")) +- throw new ActorInitializationException(""actor name must not be null, empty or start with $"") +- provider.actorOf(systemImpl, props, guardian, name, false) +- } ++ def actorOf(props: Props, name: String): ActorRef + ++ /** ++ * Create new actor of the given type as child of this context and give it an automatically ++ * generated name (currently similar to base64-encoded integer count, ++ * reversed and with “$” prepended, may change in the future). The type must have ++ * a no-arg constructor which will be invoked using reflection. ++ */ + def actorOf[T <: Actor](implicit m: Manifest[T]): ActorRef = actorOf(Props(m.erasure.asInstanceOf[Class[_ <: Actor]])) + ++ /** ++ * Create new actor of the given type as child of this context with the given name, which must ++ * not be null, empty or start with “$”. If the given name is already in use, ++ * and `InvalidActorNameException` is thrown. The type must have ++ * a no-arg constructor which will be invoked using reflection. ++ */ + def actorOf[T <: Actor](name: String)(implicit m: Manifest[T]): ActorRef = + actorOf(Props(m.erasure.asInstanceOf[Class[_ <: Actor]]), name) + ++ /** ++ * Create new actor of the given class as child of this context and give it an automatically ++ * generated name (currently similar to base64-encoded integer count, ++ * reversed and with “$” prepended, may change in the future). The class must have ++ * a no-arg constructor which will be invoked using reflection. ++ */ + def actorOf[T <: Actor](clazz: Class[T]): ActorRef = actorOf(Props(clazz)) + ++ /** ++ * Create new actor as child of this context and give it an automatically ++ * generated name (currently similar to base64-encoded integer count, ++ * reversed and with “$” prepended, may change in the future). Use this ++ * method to pass constructor arguments to the [[akka.actor.Actor]] while using ++ * only default [[akka.actor.Props]]; otherwise refer to `actorOf(Props)`. ++ */ + def actorOf(factory: ⇒ Actor): ActorRef = actorOf(Props(() ⇒ factory)) + ++ /** ++ * ''Java API'': Create new actor as child of this context and give it an ++ * automatically generated name (currently similar to base64-encoded integer ++ * count, reversed and with “$” prepended, may change in the future). ++ * ++ * Identical to `actorOf(Props(() => creator.create()))`. ++ */ + def actorOf(creator: UntypedActorFactory): ActorRef = actorOf(Props(() ⇒ creator.create())) + +- def actorFor(path: ActorPath): Option[ActorRef] = actorFor(path.path) ++ /** ++ * ''Java API'': Create new actor as child of this context with the given name, which must ++ * not be null, empty or start with “$”. If the given name is already in use, ++ * and `InvalidActorNameException` is thrown. ++ * ++ * Identical to `actorOf(Props(() => creator.create()), name)`. ++ */ ++ def actorOf(creator: UntypedActorFactory, name: String): ActorRef = actorOf(Props(() ⇒ creator.create()), name) + +- def actorFor(path: String): Option[ActorRef] = actorFor(ActorPath.split(path)) ++ /** ++ * Look-up an actor by path; if it does not exist, returns a reference to ++ * the dead-letter mailbox of the [[akka.actor.ActorSystem]]. If the path ++ * point to an actor which is not local, no attempt is made during this ++ * call to verify that the actor it represents does exist or is alive; use ++ * `watch(ref)` to be notified of the target’s termination, which is also ++ * signaled if the queried path cannot be resolved. ++ */ ++ def actorFor(path: ActorPath): ActorRef = provider.actorFor(path) + +- def actorFor(path: Iterable[String]): Option[ActorRef] = provider.actorFor(path) ++ /** ++ * Look-up an actor by path represented as string. ++ * ++ * Absolute URIs like `akka://appname/user/actorA` are looked up as described ++ * for look-ups by `actorOf(ActorPath)`. ++ * ++ * Relative URIs like `/service/actorA/childB` are looked up relative to the ++ * root path of the [[akka.actor.ActorSystem]] containing this factory and as ++ * described for look-ups by `actorOf(Iterable[String])`. ++ * ++ * Relative URIs like `myChild/grandChild` or `../myBrother` are looked up ++ * relative to the current context as described for look-ups by ++ * `actorOf(Iterable[String])` ++ */ ++ def actorFor(path: String): ActorRef = provider.actorFor(lookupRoot, path) ++ ++ /** ++ * Look-up an actor by applying the given path elements, starting from the ++ * current context, where `""..""` signifies the parent of an actor. ++ * ++ * Example: ++ * {{{ ++ * class MyActor extends Actor { ++ * def receive = { ++ * case msg => ++ * ... ++ * val target = context.actorFor(Seq("".."", ""myBrother"", ""myNephew"")) ++ * ... ++ * } ++ * } ++ * }}} ++ * ++ * For maximum performance use a collection with efficient head & tail operations. ++ */ ++ def actorFor(path: Iterable[String]): ActorRef = provider.actorFor(lookupRoot, path) ++ ++ /** ++ * Look-up an actor by applying the given path elements, starting from the ++ * current context, where `""..""` signifies the parent of an actor. ++ * ++ * Example: ++ * {{{ ++ * public class MyActor extends UntypedActor { ++ * public void onReceive(Object msg) throws Exception { ++ * ... ++ * final List path = new ArrayList(); ++ * path.add(""..""); ++ * path.add(""myBrother""); ++ * path.add(""myNephew""); ++ * final ActorRef target = context().actorFor(path); ++ * ... ++ * } ++ * } ++ * }}} ++ * ++ * For maximum performance use a collection with efficient head & tail operations. ++ */ ++ def actorFor(path: java.util.List[String]): ActorRef = { ++ import scala.collection.JavaConverters._ ++ provider.actorFor(lookupRoot, path.asScala) ++ } ++ ++ /** ++ * Construct an [[akka.actor.ActorSelection]] from the given path, which is ++ * parsed for wildcards (these are replaced by regular expressions ++ * internally). No attempt is made to verify the existence of any part of ++ * the supplied path, it is recommended to send a message and gather the ++ * replies in order to resolve the matching set of actors. ++ */ ++ def actorSelection(path: String): ActorSelection = ActorSelection(lookupRoot, path) + } + + class ActorRefProviderException(message: String) extends AkkaException(message) + ++private[akka] case class CreateChild(props: Props, name: String) ++ + /** + * Local ActorRef provider. + */ + class LocalActorRefProvider( ++ _systemName: String, + val settings: ActorSystem.Settings, + val eventStream: EventStream, + val scheduler: Scheduler, +- val rootPath: ActorPath, +- val nodename: String, +- val clustername: String) extends ActorRefProvider { ++ val deadLetters: InternalActorRef) extends ActorRefProvider { + +- def this(settings: ActorSystem.Settings, eventStream: EventStream, scheduler: Scheduler) { +- this(settings, eventStream, scheduler, new RootActorPath(LocalOnly), ""local"", ""local"") +- } ++ val rootPath: ActorPath = new RootActorPath(LocalAddress(_systemName)) ++ ++ // FIXME remove both","These two are :( +",9d7597c7282711889d74bd9b4d7bdae5ea254104 +160227,0,"Alright, I'll revise the code accordingly.""",2011-10-07 06:43:07,kro,akka,akka,,https://github.com/akka/akka-core/pull/91#discussion_r160227,2011-10-07T18:43:07Z,2011-10-07T18:43:07Z,kro,NONE,akka-zeromq/src/main/scala/akka/zeromq/AbstractSocketActor.scala,,13.0,,,13,"@@ -0,0 +1,46 @@ ++/** ++ * Copyright (C) 2009-2011 Typesafe Inc. ++ */ ++package akka.zeromq ++ ++import akka.actor.Actor ++import org.zeromq.ZMQ.Socket ++import org.zeromq.{ZMQ => ZeroMQ} ++ ++private[zeromq] abstract class AbstractSocketActor(socketType: Int, params: SocketParameters) extends Actor { ++ protected var remoteSocket: Socket = _ ++ protected def bindOrConnectRemoteSocket = self.supervisor.foreach { sup => ++ remoteSocket = (sup ? SocketRequest(socketType)).get.asInstanceOf[Socket]","Alright, I'll revise the code accordingly. +",ff32eb7654db0f2418aeb4a04131e0922c5abbd4 +383588,1,"just extract method, man :)""",2012-01-25 01:00:19,piotrga,akka,akka,,https://github.com/akka/akka-core/pull/245#discussion_r383588,2012-01-25T12:00:19Z,2012-01-25T12:00:19Z,piotrga,CONTRIBUTOR,akka-camel/src/test/scala/akka/camel/ProducerRegistryTest.scala,,45.0,,,45,"@@ -0,0 +1,59 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++ ++package akka.camel ++ ++import org.scalatest.matchers.MustMatchers ++import org.scalatest.WordSpec ++import akka.camel.TestSupport.SharedCamelSystem ++import akka.actor.Props ++import akka.util.duration._ ++ ++class ProducerRegistryTest extends WordSpec with MustMatchers with SharedCamelSystem { ++ ""A ProducerRegistry"" must { ++ ""register a started SendProcessor for the producer, which is stopped when the actor is stopped"" in { ++ val actorRef = system.actorOf(Props(behavior = ctx ⇒ { ++ case _ ⇒ {} ++ })) ++ val (endpoint, processor) = camel.registerProducer(actorRef, ""mock:mock"") ++ camel.awaitActivation(actorRef, 1 second) ++ processor.isStarted must be(true) ++ endpoint.getCamelContext must equal(camel.context) ++ system.stop(actorRef) ++ camel.awaitDeactivation(actorRef, 1 second) ++ if (!processor.isStopping) { ++ processor.isStopped must be(true) ++ } ++ } ++ ""remove and stop the SendProcessor if the actorRef is registered"" in { ++ val actorRef = system.actorOf(Props(behavior = ctx ⇒ { ++ case _ ⇒ {} ++ })) ++ val (_, processor) = camel.registerProducer(actorRef, ""mock:mock"") ++ camel.remove(actorRef) ++ if (!processor.isStopping) { ++ processor.isStopped must be(true) ++ } ++ } ++ ""remove and stop only the SendProcessor for the actorRef that is registered"" in { ++ val actorRef1 = system.actorOf(Props(behavior = ctx ⇒ { ++ case _ ⇒ {} ++ })) ++ val actorRef2 = system.actorOf(Props(behavior = ctx ⇒ { ++ case _ ⇒ {} ++ }))","just extract method, man :) +",f6646051f79f6f3c7fb3214652bce46034efed9d +386009,1,"re: """"Use Props.empty instead guys."""" Genious. And obviously it's in the docs... I just read it... :)""",2012-01-25 11:57:37,piotrga,akka,akka,,https://github.com/akka/akka-core/pull/245#discussion_r386009,2012-01-25T22:57:37Z,2012-01-25T22:57:37Z,piotrga,CONTRIBUTOR,akka-camel/src/test/scala/akka/camel/ProducerRegistryTest.scala,,45.0,,,45,"@@ -0,0 +1,59 @@ ++/** ++ * Copyright (C) 2009-2012 Typesafe Inc. ++ */ ++ ++package akka.camel ++ ++import org.scalatest.matchers.MustMatchers ++import org.scalatest.WordSpec ++import akka.camel.TestSupport.SharedCamelSystem ++import akka.actor.Props ++import akka.util.duration._ ++ ++class ProducerRegistryTest extends WordSpec with MustMatchers with SharedCamelSystem { ++ ""A ProducerRegistry"" must { ++ ""register a started SendProcessor for the producer, which is stopped when the actor is stopped"" in { ++ val actorRef = system.actorOf(Props(behavior = ctx ⇒ { ++ case _ ⇒ {} ++ })) ++ val (endpoint, processor) = camel.registerProducer(actorRef, ""mock:mock"") ++ camel.awaitActivation(actorRef, 1 second) ++ processor.isStarted must be(true) ++ endpoint.getCamelContext must equal(camel.context) ++ system.stop(actorRef) ++ camel.awaitDeactivation(actorRef, 1 second) ++ if (!processor.isStopping) { ++ processor.isStopped must be(true) ++ } ++ } ++ ""remove and stop the SendProcessor if the actorRef is registered"" in { ++ val actorRef = system.actorOf(Props(behavior = ctx ⇒ { ++ case _ ⇒ {} ++ })) ++ val (_, processor) = camel.registerProducer(actorRef, ""mock:mock"") ++ camel.remove(actorRef) ++ if (!processor.isStopping) { ++ processor.isStopped must be(true) ++ } ++ } ++ ""remove and stop only the SendProcessor for the actorRef that is registered"" in { ++ val actorRef1 = system.actorOf(Props(behavior = ctx ⇒ { ++ case _ ⇒ {} ++ })) ++ val actorRef2 = system.actorOf(Props(behavior = ctx ⇒ { ++ case _ ⇒ {} ++ }))","re: ""Use Props.empty instead guys."" +Genious. And obviously it's in the docs... I just read it... :) +",f6646051f79f6f3c7fb3214652bce46034efed9d diff --git a/data/PR inline comments/android_sentiment_pr_inline_comments_joined.csv b/data/PR inline comments/android_sentiment_pr_inline_comments_joined.csv new file mode 100644 index 0000000..9b184fd --- /dev/null +++ b/data/PR inline comments/android_sentiment_pr_inline_comments_joined.csv @@ -0,0 +1,81 @@ +comment_id,polarity,text,created_at_gold,author_login,owner,repo,review_id,html_url,created_at_kaiaulu,updated_at,comment_user_login,author_association,file_path,start_line,line,original_start_line,original_line,position,diff_hunk,body,commit_id +1664046,0,"`GitHubAccountAuthenticator` sounds reasonable.""",2012-09-21 06:10:53,kevinsawicki,github,android,,https://github.com/pockethub/PocketHub/pull/224#discussion_r1664046,2012-09-21T18:10:53Z,2012-09-21T18:50:50Z,kevinsawicki,CONTRIBUTOR,app/src/main/java/com/github/mobile/accounts/AccountAuthenticator.java,,,,,1,"@@ -75,7 +85,58 @@ public Bundle editProperties(AccountAuthenticatorResponse response, + public Bundle getAuthToken(AccountAuthenticatorResponse response, + Account account, String authTokenType, Bundle options) + throws NetworkErrorException { +- return null; ++ ++ final Bundle bundle = new Bundle(); ++ ++ if(!authTokenType.equals(ACCOUNT_TYPE)) return bundle; ++ ++ AccountManager am = AccountManager.get(context); ++ String username = account.name; ++ String password = am.getPassword(account); ++ ++ String authToken = null; ++ DefaultClient client = new DefaultClient(); ++ client.setCredentials(username, password); ++ ++ OAuthService oAuthService = new OAuthService(client); ++ ++ // Get authorizations for app if they exist ++ try { ++ try { ++ List auths = oAuthService.getAuthorizations(); ++ for(Authorization auth : auths) ++ if(auth.getApp().getName().equals(ACCOUNT_NAME)) ++ authToken = auth.getToken(); ++ } ++ catch ( NullPointerException npe ) { } ++ ++ // Setup authorization for app if others didn't exist. ++ if(TextUtils.isEmpty(authToken)) { ++ Authorization auth = oAuthService.createAuthorization( ++ new Authorization().setNote(ACCOUNT_NAME).setUrl(APP_URL) ++ ); ++ if(auth != null) authToken = auth.getToken(); ++ } ++ ++ // If couldn't get authToken ++ if(TextUtils.isEmpty(authToken)) { ++ final Intent intent = new Intent(context, LoginActivity.class); ++ intent.putExtra(PARAM_AUTHTOKEN_TYPE, ACCOUNT_TYPE); ++ intent.putExtra(KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); ++ bundle.putParcelable(KEY_INTENT, intent); ++ return bundle; ++ } ++ ++ // Assemble and return bundle ++ bundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); ++ bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE); ++ bundle.putString(AccountManager.KEY_AUTHTOKEN, authToken); ++ ++ // Clear password from account ++ am.clearPassword(account); ++ return bundle; ++ } catch ( Exception e ) { e.printStackTrace(); }","`GitHubAccountAuthenticator` sounds reasonable. +",e70b701b4b7bd5e2dc5cc00ba82605689c3723fb +1663939,1,"Yes! I'll do that. On Fri, Sep 21, 2012 at 12:57 PM, Kevin Sawicki wrote: > In app/src/main/java/com/github/mobile/AuthorizationClient.java: > > > @@ -0,0 +1,68 @@ > > +/* > > This class can be removed now right? > >""",2012-09-21 06:00:32,TrevorBasinger,github,android,,https://github.com/pockethub/PocketHub/pull/224#discussion_r1663939,2012-09-21T18:00:32Z,2012-09-21T18:50:50Z,TrevorBasinger,CONTRIBUTOR,app/src/main/java/com/github/mobile/AuthorizationClient.java,,,,,1,"@@ -0,0 +1,68 @@ ++/*","Yes! I'll do that. + +On Fri, Sep 21, 2012 at 12:57 PM, Kevin Sawicki notifications@github.comwrote: + +> In app/src/main/java/com/github/mobile/AuthorizationClient.java: +> +> > @@ -0,0 +1,68 @@ +> > +/* +> +> This class can be removed now right? +> +> — +> Reply to this email directly or view it on GitHubhttps://github.com/github/android/pull/224/files#r1663907. +",e70b701b4b7bd5e2dc5cc00ba82605689c3723fb +1222306,2,"Shame on me. You are absolutely right. I reworked the commit according to your comments.""",2012-07-23 17:37:37,Bananeweizen,github,android,,https://github.com/pockethub/PocketHub/pull/145#discussion_r1222306,2012-07-24T05:37:37Z,2012-07-24T05:37:37Z,Bananeweizen,CONTRIBUTOR,app/src/main/java/com/github/mobile/ui/commit/DiffStyler.java,,,,,1,"@@ -72,7 +72,10 @@ public DiffStyler setFiles(final Collection files) { + StyledText styled = new StyledText(); + while (end != -1) { + String line = patch.substring(start, end + 1); +- switch (patch.charAt(start)) { ++ if (line.length() == 0) { ++ continue;","Shame on me. You are absolutely right. I reworked the commit according to your comments. +",d1e578a144299d4a7e1cfcc1705f6d4502152f91 diff --git a/data/PR inline comments/automapper_sentiment_pr_inline_comments_joined.csv b/data/PR inline comments/automapper_sentiment_pr_inline_comments_joined.csv new file mode 100644 index 0000000..fb16bbf --- /dev/null +++ b/data/PR inline comments/automapper_sentiment_pr_inline_comments_joined.csv @@ -0,0 +1,18 @@ +comment_id,polarity,text,created_at_gold,author_login,owner,repo,review_id,html_url,created_at_kaiaulu,updated_at,comment_user_login,author_association,file_path,start_line,line,original_start_line,original_line,position,diff_hunk,body,commit_id +15859,2,"ok, sorry""",2011-04-05 21:59:44,andreialecu,AutoMapper,AutoMapper,,https://github.com/LuckyPennySoftware/AutoMapper/pull/29#discussion_r15859,2011-04-06T09:59:44Z,2011-04-06T10:01:28Z,andreialecu,CONTRIBUTOR,src/AutoMapper/Mappers/CollectionMapper.cs,,55.0,,,11,"@@ -48,11 +48,25 @@ namespace AutoMapper.Mappers + + protected override TCollection CreateDestinationObjectBase(Type destElementType, int sourceLength) + { +- var list = typeof(TCollection).IsInterface +- ? new List() +- : ObjectCreator.CreateDefaultValue(typeof (TCollection)); ++ Object collection; ++ ++ if (typeof(TCollection).IsInterface) ++ { ++ if (typeof(TCollection).Name == ""ISet`1"") ","A strong typed alternative to this would be: + +``` +if (typeof (TCollection).GetGenericTypeDefinition() == typeof (ISet<>)) +``` +",5492f5c2ed075c609e90c788ff4d43e97539cc4d diff --git a/data/PR inline comments/bitcoin_sentiment_pr_inline_comments_joined.csv b/data/PR inline comments/bitcoin_sentiment_pr_inline_comments_joined.csv new file mode 100644 index 0000000..524ea23 --- /dev/null +++ b/data/PR inline comments/bitcoin_sentiment_pr_inline_comments_joined.csv @@ -0,0 +1,800 @@ +comment_id,polarity,text,created_at_gold,author_login,owner,repo,review_id,html_url,created_at_kaiaulu,updated_at,comment_user_login,author_association,file_path,start_line,line,original_start_line,original_line,position,diff_hunk,body,commit_id +1119406,1,"ok! :)""",2012-07-08 04:54:02,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1469#discussion_r1119406,2012-07-08T16:54:02Z,2012-07-08T16:54:02Z,Diapolo,NONE,src/qt/addressbookpage.cpp,,204.0,,,45,"@@ -182,7 +186,25 @@ void AddressBookPage::on_signMessage_clicked() + QObject *qoGUI = parent()->parent(); + BitcoinGUI *gui = qobject_cast(qoGUI); + if (gui) +- gui->gotoMessagePage(addr); ++ gui->gotoSignMessageTab(addr); ++} ++ ++void AddressBookPage::on_verifyMessage_clicked() ++{ ++ QTableView *table = ui->tableView; ++ QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); ++ QString addr; ++ ++ foreach (QModelIndex index, indexes) ++ { ++ QVariant address = index.data(); ++ addr = address.toString(); ++ } ++ ++ QObject *qoGUI = parent()->parent();","@laanwj See #1569 for a fix for this. +",47894585aeaa4f5475c50bc4415ed6ced868fbf7 +3644466,1,"I'll add a ToDo in my local build :).""",2013-04-03 08:24:12,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2452#discussion_r3644466,2013-04-03T20:24:12Z,2013-04-03T20:24:12Z,Diapolo,NONE,src/qt/bitcoingui.h,,63.0,,,25,"@@ -56,9 +57,17 @@ class BitcoinGUI : public QMainWindow + + bool addWallet(const QString& name, WalletModel *walletModel); + bool setCurrentWallet(const QString& name); +- ++ + void removeAllWallets(); + ++ /** Used by WalletView to allow access to needed QActions */","I'll add a ToDo in my local build :). +",8726de26ee0010eaf64d44d69cc9b8e09e580a37 +2832316,1,"@luke-jr See #2217 ^^ someone just needs to do this.""",2013-01-30 08:58:06,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2247#discussion_r2832316,2013-01-30T19:58:06Z,2013-01-30T19:58:06Z,Diapolo,NONE,COPYING,,1.0,,,2,"@@ -1,4 +1,4 @@ +-Copyright (c) 2009-2012 Bitcoin Developers ++Copyright (c) 2009-2013 Bitcoin Developers","@luke-jr See #2217 ^^ someone just needs to do this. +",d38c6488d067c2e88726e2ca99bc76fd67dab49b +1928306,0,"Agree, in this case, it's an optimization not needing to calculate the hash.""",2012-10-24 01:36:53,sipa,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1953#discussion_r1928306,2012-10-24T13:36:53Z,2012-10-24T13:36:53Z,sipa,MEMBER,src/main.cpp,,1561.0,,,4,"@@ -1558,7 +1558,8 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust + // Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the + // two in the chain that violate it. This prevents exploiting the issue against nodes in their + // initial block download. +- bool fEnforceBIP30 = !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256(""0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec"")) ||","Agree, in this case, it's an optimization not needing to calculate the hash. +",faff50d129b6d4b9e6397ac989218e83a26ae692 +1449572,0,"@laanwj What do you say? Is the general idea for that reset button a good one and what about the detach thing?""",2012-08-23 09:50:50,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1685#discussion_r1449572,2012-08-23T21:50:50Z,2013-01-05T12:52:15Z,Diapolo,NONE,src/qt/optionsmodel.cpp,,,,,1,"@@ -167,7 +185,7 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const + case DisplayAddresses: + return QVariant(bDisplayAddresses); + case DetachDatabases: +- return QVariant(bitdb.GetDetach()); ++ return settings.value(""detachDB"", false);","@laanwj What do you say? Is the general idea for that reset button a good one and what about the detach thing? +",5fb445b49e80812f004f00d5adf8fdd39bec557f +1366333,1,"So everything fine here :)?""",2012-08-13 08:39:34,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1649#discussion_r1366333,2012-08-13T20:39:34Z,2012-08-13T20:39:34Z,Diapolo,NONE,src/qt/optionsdialog.cpp,,154.0,,,33,"@@ -147,6 +150,16 @@ void OptionsDialog::setMapper() + mapper->addMapping(ui->displayAddresses, OptionsModel::DisplayAddresses); + } + ++void OptionsDialog::enableApplyButton() ++{","So everything fine here :)? +",4aaa4313e7edf5d23143e393efd2d5892d5dde48 +974400,0,"If you add `TODO:` in the comment, many code editors will show it in an overview. Might be useful, and more clear to readers that it isn't just commented out code (otherwise, someone that doesn't know might remove it).""",2012-06-12 20:36:14,laanwj,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1405#discussion_r974400,2012-06-13T08:36:14Z,2012-06-13T08:36:14Z,laanwj,MEMBER,src/db.cpp,,658.0,,,138,"@@ -535,6 +551,118 @@ CBlockIndex static * InsertBlockIndex(uint256 hash) + return pindexNew; + } + ++bool CTxDB::PruneBlockIndex(uint256 hashPruneFrom, uint256 hashPruneTo) ++{ ++// TODO: assert here, but cant #include main.h ++// if (hashPruneFrom != 0) ++// assert(hashPruneTo == hashBestBlock); ++ ++ CBlockIndex* pindexScan = pindexGenesisBlock; ++ uint256 hashOldBestCheckpoint; ++ if (ReadHashBestCheckpoint(hashOldBestCheckpoint) && hashOldBestCheckpoint == hashPruneTo) ++ return true; ++ ++ if (!mapBlockIndex.count(hashPruneTo)) ++ return true; ++ ++ if (hashPruneFrom != 0) ++ pindexScan = mapBlockIndex[hashPruneFrom]; ++ assert(pindexScan); ++ ++ printf(""Pruning Block Index from %s to %s.\n"", hashPruneFrom.ToString().substr(0,20).c_str(), hashPruneTo.ToString().substr(0,20).c_str()); ++ ++ // Cache of Txes by hash -> txouts spent before hashPruneTo flags + cant be deleted flag ++ map, bool> > mapTxIndexCache; ++ ++ while (pindexScan != NULL && *(pindexScan->phashBlock) != hashPruneTo) ++ { ++ if(fRequestShutdown) ++ return true; ++ ++ CBlock block; ++ block.ReadFromDisk(pindexScan); ++ ++ BOOST_FOREACH(CTransaction& tx, block.vtx) ++ { ++ if (tx.IsCoinBase()) ++ continue; ++ ++ BOOST_FOREACH(CTxIn& txin, tx.vin) ++ { ++ COutPoint& txout = txin.prevout; ++ uint256& hash = txout.hash; ++ pair, bool>& pairTx = mapTxIndexCache[hash]; ++ ++ if (pairTx.first.size() == 0) ++ { ++ CTxIndex txindex; ++ if (!ReadTxIndex(hash, txindex)) ++ { ++ // This should only ever happen if we get interrupted pruning and dont WriteHashBestCheckpoint ++ pairTx.second = false; ++ break; ++ } ++ ++ vector& vSpent = txindex.vSpent; ++ unsigned int vouts = vSpent.size(); ++ ++ pairTx.first.resize(vouts); ++ ++ pairTx.second = true; ++ for (unsigned int i = 0; i < vouts; i++) ++ { ++ if (vSpent[i].IsNull()) ++ { ++ pairTx.second = false; ++ break; ++ } ++ pairTx.first[i] = false; ++ } ++ } ++ ++ if (pairTx.second == false) ++ continue; ++ ++ pairTx.first[txout.n] = true; ++ } ++ } ++ ++ pindexScan = pindexScan->pnext; ++ } ++ ++ // TODO: It may be prudent to use DB Transactions here, but if we do we overrun our maximum lock objects ++ //if (!TxnBegin()) ++ // return false; ++ ++ unsigned int nTxsPruned = 0; ++ typedef pair, bool> > TxIndexCachePairType; ++ BOOST_FOREACH(TxIndexCachePairType& pair, mapTxIndexCache) ++ { ++ bool fPrunable = true; ++ BOOST_FOREACH(bool fSpent, pair.second.first) ++ if (!fSpent) ++ { ++ fPrunable = false; ++ break; ++ } ++ ++ if (!fPrunable) ++ continue; ++ ++ EraseTxIndex(pair.first); ++ nTxsPruned++; ++ } ++ ++ WriteHashBestCheckpoint(hashPruneTo); ++ ++ //if (!TxnCommit())","If you add `TODO:` in the comment, many code editors will show it in an overview. Might be useful, and more clear to readers that it isn't just commented out code (otherwise, someone that doesn't know might remove it). +",24f4c50f2997bfc9e374c26b25e234dea549774f +775694,1,"Didn't know that, but I think the names are more speaking than a simple -1 :), look how we guessed what that -1 means here. Would not have happend if we used the error codes.""",2012-05-04 05:48:34,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1180#discussion_r775694,2012-05-04T17:48:34Z,2012-05-04T17:48:34Z,Diapolo,NONE,src/net.cpp,,624.0,,,5,"@@ -621,7 +621,7 @@ void ThreadSocketHandler2(void* parg) + if (nSelect == SOCKET_ERROR) + { + int nErr = WSAGetLastError(); +- if (hSocketMax > -1) ++ if (hSocketMax > (SOCKET) -1)","Didn't know that, but I think the names are more speaking than a simple -1 :), look how we guessed what that -1 means here. Would not have happend if we used the error codes. +",024fa1cb44b8ec577fef07e7b37a4e5b0501dbea +1637626,2,"If all who contribute translatable strings to the source would be a little more straight there would be no need for this. It really annoys me, that we have strings that have incorrect grammar or punctuation. At least for the string """"Error: Transaction cr""",2012-09-18 20:50:10,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1830#discussion_r1637626,2012-09-19T08:50:10Z,2012-10-25T20:34:18Z,Diapolo,NONE,src/qt/sendcoinsdialog.cpp,,151.0,,,5,"@@ -148,7 +148,7 @@ void SendCoinsDialog::on_sendButton_clicked() + break; + case WalletModel::TransactionCreationFailed: + QMessageBox::warning(this, tr(""Send Coins""), +- tr(""Error: Transaction creation failed.""), ++ tr(""Error: Transaction creation failed!""),","If all who contribute translatable strings to the source would be a little more straight there would be no need for this. +It really annoys me, that we have strings that have incorrect grammar or punctuation. + +At least for the string ""Error: Transaction creation failed."" we currently already have 2 strings in the translations, this pull makes one out of them. + +You are free to close such pulls you consider not valuable, even if I don't agree here, as a good overall string handling was needed badly and this covers the last things I could find! +",6b3783a9c9cc47afcf72aa0a86ea26122392efdb +1681635,0,"No problem here, it is entirely correct: calling itostr casts the unsigned short to a signed integer (which is larger, so there is never undefined behavior), before feeding it into strprintf as a signed integer (%d). """,2012-09-24 20:46:54,laanwj,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1862#discussion_r1681635,2012-09-25T08:46:54Z,2012-09-25T08:46:54Z,laanwj,MEMBER,src/bitcoinrpc.cpp,,1063.0,,,26,"@@ -1055,7 +1060,7 @@ Object CallRPC(const string& strMethod, const Array& params) + asio::ssl::stream sslStream(io_service, context); + SSLIOStreamDevice d(sslStream, fUseSSL); + iostreams::stream< SSLIOStreamDevice > stream(d); +- if (!d.connect(GetArg(""-rpcconnect"", ""127.0.0.1""), GetArg(""-rpcport"", ""8332""))) ++ if (!d.connect(GetArg(""-rpcconnect"", ""127.0.0.1""), GetArg(""-rpcport"", itostr(GetDefaultRPCPort()))))","No problem here, it is entirely correct: calling itostr casts the unsigned short to a signed integer (which is larger, so there is never undefined behavior), before feeding it into strprintf as a signed integer (%d). +",b202d430762c1b5c9925e948f357c66040f95f10 +1118206,2,"I don't really like this code as it makes assumptions about the parent object and does explicit casts. Why not use a signal 'verifyMessage(QString addr)'?""",2012-07-06 23:48:13,laanwj,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1469#discussion_r1118206,2012-07-07T11:48:13Z,2012-07-07T11:48:13Z,laanwj,MEMBER,src/qt/addressbookpage.cpp,,204.0,,,45,"@@ -182,7 +186,25 @@ void AddressBookPage::on_signMessage_clicked() + QObject *qoGUI = parent()->parent(); + BitcoinGUI *gui = qobject_cast(qoGUI); + if (gui) +- gui->gotoMessagePage(addr); ++ gui->gotoSignMessageTab(addr); ++} ++ ++void AddressBookPage::on_verifyMessage_clicked() ++{ ++ QTableView *table = ui->tableView; ++ QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address); ++ QString addr; ++ ++ foreach (QModelIndex index, indexes) ++ { ++ QVariant address = index.data(); ++ addr = address.toString(); ++ } ++ ++ QObject *qoGUI = parent()->parent();","I don't really like this code as it makes assumptions about the parent object and does explicit casts. Why not use a signal 'verifyMessage(QString addr)'? +",47894585aeaa4f5475c50bc4415ed6ced868fbf7 +1716918,1,"Fine, same is true for me thinking about Linux ;). End of OT then ^^.""",2012-09-28 00:47:47,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1851#discussion_r1716918,2012-09-28T12:47:47Z,2012-09-28T12:47:47Z,Diapolo,NONE,doc/build-unix.txt,,50.0,,,5,"@@ -47,7 +47,7 @@ Licenses of statically linked libraries: + + Versions used in this release: + GCC 4.3.3 +- OpenSSL 0.9.8g ++ OpenSSL 1.0.1c","Fine, same is true for me thinking about Linux ;). End of OT then ^^. +",0eaaa83ba521af8453c11ad688bdbb6bd4e33870 +1527978,1,"When I now read the first comment all that makes sense ^^ you are such a patient person :-P. With your new code we would pass hSocketMax == 0 to select(), when -proxy is invalid (no BOOST_FOREACH pass), I'm not sure if this is valid. But you are right, w""",2012-09-04 09:23:01,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1772#discussion_r1527978,2012-09-04T21:23:01Z,2012-09-04T21:45:41Z,Diapolo,NONE,src/net.cpp,,787.0,,,10,"@@ -781,10 +781,9 @@ void ThreadSocketHandler2(void* parg) + return; + if (nSelect == SOCKET_ERROR) + { +- int nErr = WSAGetLastError(); +- if (hSocketMax != INVALID_SOCKET) ++ if ((hSocketMax != INVALID_SOCKET) && (hSocketMax != (SOCKET)0)) + { +- printf(""socket select error %d\n"", nErr); ++ printf(""socket select error %d\n"", WSAGetLastError()); + for (unsigned int i = 0; i <= hSocketMax; i++)","When I now read the first comment all that makes sense ^^ you are such a patient person :-P. + +With your new code we would pass hSocketMax == 0 to select(), when -proxy is invalid (no BOOST_FOREACH pass), I'm not sure if this is valid. But you are right, when hSocketMax stays 0, we have no fds set, but I'm not sure if it can ever become 1. It would be 1, if vhListenSocket or vNodes is not empty and the contained sockets are == 0. + +vhListenSocket is empty, when we are not listening and vNodes if we are not connected to any peers IMO. +",8207857f401bc1a48f863be646c5a508a7cdfe9c +2106752,2,"Satoshi is a very bad person to learn C++ style from :poodle: If you want an example of well-structured, readable C++ I can recommend reading source from LLVM. And I'm not sure either, it doesn't warrant changing all the functions I guess... maybe just l""",2012-11-12 20:31:06,laanwj,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1479#discussion_r2106752,2012-11-13T07:31:06Z,2012-11-13T07:32:59Z,laanwj,MEMBER,src/wallet.cpp,,929.0,,,7,"@@ -926,9 +926,8 @@ int64 CWallet::GetImmatureBalance() const + LOCK(cs_wallet); + for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { +- const CWalletTx& pcoin = (*it).second; +- if (pcoin.IsCoinBase() && pcoin.GetBlocksToMaturity() > 0 && pcoin.IsInMainChain()) +- nTotal += GetCredit(pcoin); ++ const CWalletTx* pcoin = &(*it).second;","Satoshi is a very bad person to learn C++ style from :poodle: If you want an example of well-structured, readable C++ I can recommend reading source from LLVM. +And I'm not sure either, it doesn't warrant changing all the functions I guess... maybe just leave it like this then. +",966a0e8cc94f2590521e0a2513e0cea32b5bb005 +766482,0,"Is this code path ever followed? I mean, will an unsigned integer ever be larger than (unsigned) -1? """,2012-05-02 17:59:39,laanwj,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1180#discussion_r766482,2012-05-03T05:59:39Z,2012-05-03T05:59:39Z,laanwj,MEMBER,src/net.cpp,,624.0,,,5,"@@ -621,7 +621,7 @@ void ThreadSocketHandler2(void* parg) + if (nSelect == SOCKET_ERROR) + { + int nErr = WSAGetLastError(); +- if (hSocketMax > -1) ++ if (hSocketMax > (SOCKET) -1)","Is this code path ever followed? I mean, will an unsigned integer ever be larger than (unsigned) -1? +",024fa1cb44b8ec577fef07e7b37a4e5b0501dbea +1677922,0,"itostr() does ``strprintf(""""%d"""", n)``, which is for signed integers, so should we better use ``strprintf(""""%u"""", GetDefaultRPCPort())`` instead, as we have an unsigned short as port number?""",2012-09-24 09:10:48,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1862#discussion_r1677922,2012-09-24T21:10:48Z,2012-09-24T21:10:48Z,Diapolo,NONE,src/bitcoinrpc.cpp,,1063.0,,,26,"@@ -1055,7 +1060,7 @@ Object CallRPC(const string& strMethod, const Array& params) + asio::ssl::stream sslStream(io_service, context); + SSLIOStreamDevice d(sslStream, fUseSSL); + iostreams::stream< SSLIOStreamDevice > stream(d); +- if (!d.connect(GetArg(""-rpcconnect"", ""127.0.0.1""), GetArg(""-rpcport"", ""8332""))) ++ if (!d.connect(GetArg(""-rpcconnect"", ""127.0.0.1""), GetArg(""-rpcport"", itostr(GetDefaultRPCPort()))))","itostr() does `strprintf(""%d"", n)`, which is for signed integers, so should we better use `strprintf(""%u"", GetDefaultRPCPort())` instead, as we have an unsigned short as port number? +",b202d430762c1b5c9925e948f357c66040f95f10 +1679137,0,"My understanding is that this is well defined. The implicit type conversion is from unsigned short to signed int, which is always safe. (Since the short is unsigned, there is no sign to extend.) The compiler doesn't even blink at this with -Wall, but i""",2012-09-24 11:49:15,kjj2,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1862#discussion_r1679137,2012-09-24T23:49:15Z,2012-09-24T23:49:15Z,kjj2,NONE,src/bitcoinrpc.cpp,,1063.0,,,26,"@@ -1055,7 +1060,7 @@ Object CallRPC(const string& strMethod, const Array& params) + asio::ssl::stream sslStream(io_service, context); + SSLIOStreamDevice d(sslStream, fUseSSL); + iostreams::stream< SSLIOStreamDevice > stream(d); +- if (!d.connect(GetArg(""-rpcconnect"", ""127.0.0.1""), GetArg(""-rpcport"", ""8332""))) ++ if (!d.connect(GetArg(""-rpcconnect"", ""127.0.0.1""), GetArg(""-rpcport"", itostr(GetDefaultRPCPort()))))","My understanding is that this is well defined. The implicit type conversion is from unsigned short to signed int, which is always safe. (Since the short is unsigned, there is no sign to extend.) The compiler doesn't even blink at this with -Wall, but it does gripe often about the 3 lines in net.h that assign a literal -1 to an unsigned int. +",b202d430762c1b5c9925e948f357c66040f95f10 +1680583,1,"Alright I'm fine with this patch then, but now I'm interested in which lines give you that signed/unsigned warning, as we are always interested in finding and fixing these :).""",2012-09-24 17:03:10,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1862#discussion_r1680583,2012-09-25T05:03:10Z,2012-09-25T05:03:10Z,Diapolo,NONE,src/bitcoinrpc.cpp,,1063.0,,,26,"@@ -1055,7 +1060,7 @@ Object CallRPC(const string& strMethod, const Array& params) + asio::ssl::stream sslStream(io_service, context); + SSLIOStreamDevice d(sslStream, fUseSSL); + iostreams::stream< SSLIOStreamDevice > stream(d); +- if (!d.connect(GetArg(""-rpcconnect"", ""127.0.0.1""), GetArg(""-rpcport"", ""8332""))) ++ if (!d.connect(GetArg(""-rpcconnect"", ""127.0.0.1""), GetArg(""-rpcport"", itostr(GetDefaultRPCPort()))))","Alright I'm fine with this patch then, but now I'm interested in which lines give you that signed/unsigned warning, as we are always interested in finding and fixing these :). +",b202d430762c1b5c9925e948f357c66040f95f10 +3689433,1,"Because the old text """"src/qt/res/src/*.svg"""" had covered the newly generated src/qt/res/src/bitcoin.svg i had to """"rewrite it arithmetically"""". :) I think it's okay like this.""",2013-04-07 19:10:57,jonasschnelli,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2477#discussion_r3689433,2013-04-08T07:10:57Z,2013-04-08T08:37:30Z,jonasschnelli,CONTRIBUTOR,doc/assets-attribution.txt,,3.0,,,4,"@@ -1,5 +1,8 @@ + Icon: src/qt/res/icons/clock*.png, src/qt/res/icons/tx*.png, +- src/qt/res/src/*.svg ++ src/qt/res/src/clock_green.svg, src/qt/res/src/clock1.svg ++ src/qt/res/src/clock2.svg, src/qt/res/src/clock3.svg","Because the old text ""src/qt/res/src/*.svg"" had covered the newly generated src/qt/res/src/bitcoin.svg i had to ""rewrite it arithmetically"". :) +I think it's okay like this. +",a653191f748f56addf0cfa219319cfc5358b962d +3686931,0,"Why not a single mapSigHashCache for the whole EvalScript evaluation?""",2013-04-07 06:29:02,sipa,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2275#discussion_r3686931,2013-04-07T18:29:02Z,2013-04-08T23:50:28Z,sipa,MEMBER,src/script.cpp,,,,,1,"@@ -1061,16 +1064,29 @@ bool EvalScript(vector >& stack, const CScript& script, co + scriptCode.FindAndDelete(CScript(vchSig)); + } + ++ // Avoid repeatedly recomputing signature hashes ++ map mapSigHashCache;","Why not a single mapSigHashCache for the whole EvalScript evaluation? +",61a29a7c0676eb0d422ff828f0ba006ba0fc8e2e +847483,0,"This should be moved into the for loop, IMO: ```C++ for(unsigned int idx = 0; idx < input.size(); removeChar ? input.remove(idx, 1) : ++idx) ``` (also changed idx type to unsigned since it is compared with .size()) """,2012-05-18 07:36:41,luke-jr,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1329#discussion_r847483,2012-05-18T19:36:41Z,2012-05-21T16:53:31Z,luke-jr,MEMBER,src/qt/bitcoinaddressvalidator.cpp,,44.0,,,33,"@@ -21,21 +21,28 @@ + QValidator::State BitcoinAddressValidator::validate(QString &input, int &pos) const + { + // Correction +- for(int idx=0; idxstream << HTTPReply(200, strReply, fRun) << std::flush; + } + catch (std::exception& e) + { +- ErrorReply(stream, JSONRPCError(-1, e.what()), id); ++ ErrorReply(conn->stream, JSONRPCError(-1, e.what()), id); ++ fRun = false; ++ } ++ catch (Object& e) ++ { ++ ErrorReply(conn->stream, e, id); ++ fRun = false; + } + } + catch (Object& objError) + { +- ErrorReply(stream, objError, id); ++ ErrorReply(conn->stream, objError, id); ++ break; + } + catch (std::exception& e) + { +- ErrorReply(stream, JSONRPCError(-32700, e.what()), id); ++ ErrorReply(conn->stream, JSONRPCError(-32700, e.what()), id);","Same fRun thing here too... someone should probably note whether -32700 vs -1 is the correct response? +",96c5269511b0cecbea67c0981aaea1a8a3345ba3 +268795,1,"Good catch :)""",2011-12-04 03:24:08,luke-jr,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/677#discussion_r268795,2011-12-04T14:24:08Z,2011-12-14T06:08:26Z,luke-jr,MEMBER,src/main.h,,536.0,,,23,"@@ -523,10 +530,10 @@ class CTransaction + return dPriority > COIN * 144 / 250; + } + +- int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, bool fForRelay=false) const ++ int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, enum GetMinFee_mode mode=GMF_BLOCK) const + { + // Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE +- int64 nBaseFee = fForRelay ? MIN_RELAY_TX_FEE : MIN_TX_FEE; ++ int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE;","Good catch :) +",dbbf1d4a48c8761a67a4477bef48f17c0badef7b +1660813,2,"I really don't like CBlocks storing their own reject string, seems like a layer violation. Maybe not directly related to this change, as nDoS does the same. I'd rather see a CValidationResult which stores such information, which is returned or pass-by-re""",2012-09-21 00:55:09,sipa,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1816#discussion_r1660813,2012-09-21T12:55:09Z,2014-11-20T15:33:15Z,sipa,MEMBER,src/main.h,,,,,1,"@@ -837,6 +837,8 @@ class CBlock + // Denial-of-service detection: + mutable int nDoS; + bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; } ++ mutable std::string strRejectReason; ++ bool reject(const std::string& strRejectReasonIn, bool fIn) const { strRejectReason = strRejectReasonIn; return fIn; }","I really don't like CBlocks storing their own reject string, seems like a layer violation. Maybe not directly related to this change, as nDoS does the same. + +I'd rather see a CValidationResult which stores such information, which is returned or pass-by-ref inside the block- and transaction validation functions. That's maybe out of scope for this change, though. +",b867e409e5dd34b84eb9d6d0d8f257dbb19b986d +2604303,1,"Can we keep a space after starting comments :)?""",2013-01-10 02:08:31,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2129#discussion_r2604303,2013-01-10T13:08:31Z,2013-01-10T13:08:31Z,Diapolo,NONE,src/wallet.cpp,,1157.0,,,5,"@@ -1154,7 +1154,10 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW + BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) + { + int64 nCredit = pcoin.first->vout[pcoin.second].nValue; +- dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain(); ++ //The priority after the next block (depth+1) is used instead of the current,","Can we keep a space after starting comments :)? +",d7836552e64b1f949385f7b11836ece99f7c3d67 +2487321,2,"And I still don't get the meaning in german from that weird english description...""",2012-12-20 23:22:06,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2048#discussion_r2487321,2012-12-21T10:22:06Z,2012-12-21T10:22:06Z,Diapolo,NONE,src/init.cpp,,261.0,,,4,"@@ -258,6 +258,7 @@ bool static Bind(const CService &addr, unsigned int flags) { + "" -onlynet= "" + _(""Only connect to nodes in network (IPv4, IPv6 or Tor)"") + ""\n"" + + "" -discover "" + _(""Discover own IP address (default: 1 when listening and no -externalip)"") + ""\n"" + + "" -irc "" + _(""Find peers using internet relay chat (default: 0)"") + ""\n"" + ++ "" -checkpoints "" + _(""Lock in block chain with compiled-in checkpoints (default: 1)"") + ""\n"" +","And I still don't get the meaning in german from that weird english description... +",e6955d04111e842cce55dc230d9dcc971560a299 +948155,1,"That Commented out code should be removed, if not used :).""",2012-06-07 11:21:24,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1405#discussion_r948155,2012-06-07T23:21:24Z,2012-06-07T23:21:34Z,Diapolo,NONE,src/db.cpp,,658.0,,,138,"@@ -535,6 +551,118 @@ CBlockIndex static * InsertBlockIndex(uint256 hash) + return pindexNew; + } + ++bool CTxDB::PruneBlockIndex(uint256 hashPruneFrom, uint256 hashPruneTo) ++{ ++// TODO: assert here, but cant #include main.h ++// if (hashPruneFrom != 0) ++// assert(hashPruneTo == hashBestBlock); ++ ++ CBlockIndex* pindexScan = pindexGenesisBlock; ++ uint256 hashOldBestCheckpoint; ++ if (ReadHashBestCheckpoint(hashOldBestCheckpoint) && hashOldBestCheckpoint == hashPruneTo) ++ return true; ++ ++ if (!mapBlockIndex.count(hashPruneTo)) ++ return true; ++ ++ if (hashPruneFrom != 0) ++ pindexScan = mapBlockIndex[hashPruneFrom]; ++ assert(pindexScan); ++ ++ printf(""Pruning Block Index from %s to %s.\n"", hashPruneFrom.ToString().substr(0,20).c_str(), hashPruneTo.ToString().substr(0,20).c_str()); ++ ++ // Cache of Txes by hash -> txouts spent before hashPruneTo flags + cant be deleted flag ++ map, bool> > mapTxIndexCache; ++ ++ while (pindexScan != NULL && *(pindexScan->phashBlock) != hashPruneTo) ++ { ++ if(fRequestShutdown) ++ return true; ++ ++ CBlock block; ++ block.ReadFromDisk(pindexScan); ++ ++ BOOST_FOREACH(CTransaction& tx, block.vtx) ++ { ++ if (tx.IsCoinBase()) ++ continue; ++ ++ BOOST_FOREACH(CTxIn& txin, tx.vin) ++ { ++ COutPoint& txout = txin.prevout; ++ uint256& hash = txout.hash; ++ pair, bool>& pairTx = mapTxIndexCache[hash]; ++ ++ if (pairTx.first.size() == 0) ++ { ++ CTxIndex txindex; ++ if (!ReadTxIndex(hash, txindex)) ++ { ++ // This should only ever happen if we get interrupted pruning and dont WriteHashBestCheckpoint ++ pairTx.second = false; ++ break; ++ } ++ ++ vector& vSpent = txindex.vSpent; ++ unsigned int vouts = vSpent.size(); ++ ++ pairTx.first.resize(vouts); ++ ++ pairTx.second = true; ++ for (unsigned int i = 0; i < vouts; i++) ++ { ++ if (vSpent[i].IsNull()) ++ { ++ pairTx.second = false; ++ break; ++ } ++ pairTx.first[i] = false; ++ } ++ } ++ ++ if (pairTx.second == false) ++ continue; ++ ++ pairTx.first[txout.n] = true; ++ } ++ } ++ ++ pindexScan = pindexScan->pnext; ++ } ++ ++ // TODO: It may be prudent to use DB Transactions here, but if we do we overrun our maximum lock objects ++ //if (!TxnBegin()) ++ // return false; ++ ++ unsigned int nTxsPruned = 0; ++ typedef pair, bool> > TxIndexCachePairType; ++ BOOST_FOREACH(TxIndexCachePairType& pair, mapTxIndexCache) ++ { ++ bool fPrunable = true; ++ BOOST_FOREACH(bool fSpent, pair.second.first) ++ if (!fSpent) ++ { ++ fPrunable = false; ++ break; ++ } ++ ++ if (!fPrunable) ++ continue; ++ ++ EraseTxIndex(pair.first); ++ nTxsPruned++; ++ } ++ ++ WriteHashBestCheckpoint(hashPruneTo); ++ ++ //if (!TxnCommit())","That Commented out code should be removed, if not used :). +",24f4c50f2997bfc9e374c26b25e234dea549774f +553739,2,"Do we really want to increment a full major version...not that it matters, but it seems excessive...""",2012-03-13 08:44:26,TheBlueMatt,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/932#discussion_r553739,2012-03-13T19:44:26Z,2012-03-13T19:44:26Z,TheBlueMatt,CONTRIBUTOR,src/serialize.h,,56.0,,,5,"@@ -53,7 +53,7 @@ + class CAutoFile; + static const unsigned int MAX_SIZE = 0x02000000; + +-static const int PROTOCOL_VERSION = 60000; ++static const int PROTOCOL_VERSION = 70000;","Do we really want to increment a full major version...not that it matters, but it seems excessive... +",2fef9dac628524a528263e0ac1efcb719cd8a98d +263952,0,"coding style: brace on next line""",2011-12-01 03:13:49,sipa,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/654#discussion_r263952,2011-12-01T14:13:49Z,2011-12-01T14:13:49Z,sipa,MEMBER,src/net.cpp,,1226.0,,,22,"@@ -1213,8 +1214,28 @@ static const char *strDNSSeed[] = { + ""dnsseed.bluematt.me"", + }; + +-void DNSAddressSeed() ++void ThreadDNSAddressSeed(void* parg) + { ++ IMPLEMENT_RANDOMIZE_STACK(ThreadDNSAddressSeed(parg)); ++ try ++ { ++ vnThreadsRunning[6]++; ++ ThreadDNSAddressSeed2(parg); ++ vnThreadsRunning[6]--; ++ } ++ catch (std::exception& e) {","coding style: brace on next line +",2bc6cecebba52e32db43a0b2d9b519ac4a48c479 +314387,0,"re select specific coins: If you read the original motivation for this patch it was to prevent linkages of addresses/private-keys. Selecting individual coins doesn't matter for that. re the RPC command arguments: I'm not sold that it's worth doing what """,2011-12-24 14:17:07,coderrr,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/415#discussion_r314387,2011-12-25T01:17:07Z,2012-03-23T09:45:25Z,,NONE,src/bitcoinrpc.cpp,,578.0,,,18,"@@ -498,38 +498,74 @@ Value settxfee(const Array& params, bool fHelp) + + Value sendtoaddress(const Array& params, bool fHelp) + { +- if (pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4)) ++ string crypt_usage = pwalletMain->IsCrypted() ? ""\nrequires wallet passphrase to be set with walletpassphrase first"" : """"; ++ ++ if (fHelp || params.size() < 2 || params.size() > 4) + throw runtime_error( +- ""sendtoaddress [comment] [comment-to]\n"" +- "" is a real and is rounded to the nearest 0.00000001\n"" +- ""requires wallet passphrase to be set with walletpassphrase first""); +- if (!pwalletMain->IsCrypted() && (fHelp || params.size() < 2 || params.size() > 4)) ++ ""sendtoaddress [:[,[,...]]] [comment] [comment-to]\n"" ++ "" is a real and is rounded to the nearest 0.00000001"" + crypt_usage); ++ ++ string strAddress = params[0].get_str(); ++ vector splitAddresses; ++ boost::split(splitAddresses, strAddress, boost::is_any_of("":""));","re select specific coins: If you read the original motivation for this patch it was to prevent linkages of addresses/private-keys. Selecting individual coins doesn't matter for that. + +re the RPC command arguments: I'm not sold that it's worth doing what you suggested purely because of your aversion to bitcoind parsing strings. The way it's done now is pretty minimally invasive and the other ways sound like a lot more changes. But I'd like to hear other people's opinions on the matter. +",a4d98b650bc4d644c6188ea50891a80061bb0c8b +2563520,0,"Oh, yes - you'll need compatibility with boost filesystem v2 though... for now""",2013-01-07 01:12:09,sipa,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2124#discussion_r2563520,2013-01-07T12:12:09Z,2013-09-16T21:20:57Z,sipa,MEMBER,src/util.cpp,,977.0,,,1,"@@ -944,12 +944,31 @@ bool WildcardMatch(const string& str, const string& mask) + return WildcardMatch(str.c_str(), mask.c_str()); + } + +- +- +- +- +- +- ++vector GetFilesAtPath(const boost::filesystem::path& _path, unsigned int flags) ++{ ++ vector vstrFiles; ++ if (!boost::filesystem::exists(_path)) ++ throw runtime_error(""Path does not exist.""); ++ ++ if ((flags & file_option_flags::REGULAR_FILES) && boost::filesystem::is_regular_file(_path)) ++ { ++ vstrFiles.push_back(_path.filename().string());","Oh, yes - you'll need compatibility with boost filesystem v2 though... for now +",6c7f86ae371f955371fba05c7f747e4659cd39c8 +1926227,2,"I don't really like the fact that the hash in CBlockIndex::phashBlock is optional. We have a GetBlockHash()... why doesn't it just calculate the hash if it's not available? """,2012-10-23 21:14:24,sipa,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1953#discussion_r1926227,2012-10-24T09:14:24Z,2012-10-24T09:14:44Z,sipa,MEMBER,src/main.cpp,,1561.0,,,4,"@@ -1558,7 +1558,8 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsViewCache &view, bool fJust + // Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the + // two in the chain that violate it. This prevents exploiting the issue against nodes in their + // initial block download. +- bool fEnforceBIP30 = !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256(""0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec"")) ||","I don't really like the fact that the hash in CBlockIndex::phashBlock is optional. We have a GetBlockHash()... why doesn't it just calculate the hash if it's not available? +",faff50d129b6d4b9e6397ac989218e83a26ae692 +1848920,0,"0.7.0 is a first-time stable release: it's built off master, not a stable branch. I wouldn't suggest touching the user's PGP setup, but verifying without touching it. If GPG really needs to keep keys somewhere, ~/.bitcoin/.gnupg or similar makes sense.""",2012-10-15 11:21:27,luke-jr,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1935#discussion_r1848920,2012-10-15T23:21:27Z,2012-10-15T23:21:39Z,luke-jr,MEMBER,contrib/verifysfbinaries/verify.sh,,85.0,,,85,"@@ -0,0 +1,119 @@ ++#!/bin/bash ++ ++### This script attempts to download the signature file SHA256SUMS.asc from SourceForge ++### It first checks if the signature passes, and then downloads the files specified in ++### the file, and checks if the hashes of these files match those that are specified ++### in the signature file. ++### The script returns 0 if everything passes the checks. It returns 1 if either the ++### signature check or the hash check doesn't pass. If an error occurs the return value is 2 ++ ++function clean_up { ++ for file in $* ++ do ++ rm ""$file"" 2> /dev/null ++ done ++} ++ ++WORKINGDIR=""/tmp/bitcoin"" ++TMPFILE=""hashes.tmp"" ++ ++#this URL is used if a version number is not specified as an argument to the script ++SIGNATUREFILE=""http://downloads.sourceforge.net/project/bitcoin/Bitcoin/bitcoin-0.7.1/test/SHA256SUMS.asc"" ++ ++SIGNATUREFILENAME=""SHA256SUMS.asc"" ++RCSUBDIR=""test/"" ++BASEDIR=""http://downloads.sourceforge.net/project/bitcoin/Bitcoin/"" ++VERSIONPREFIX=""bitcoin-"" ++RCVERSIONSTRING=""rc"" ++ ++if [ ! -d ""$WORKINGDIR"" ]; then ++ mkdir ""$WORKINGDIR"" ++fi ++ ++cd ""$WORKINGDIR"" ++ ++#test if a version number has been passed as an argument ++if [ -n ""$1"" ]; then ++ #let's also check if the version number includes the prefix 'bitcoin-', ++ # and add this prefix if it doesn't ++ if [[ $1 == ""$VERSIONPREFIX""* ]]; then ++ VERSION=""$1"" ++ else ++ VERSION=""$VERSIONPREFIX$1"" ++ fi ++ ++ #now let's see if the version string contains ""rc"", and strip it off if it does ++ # and simultaneously add RCSUBDIR to BASEDIR, where we will look for SIGNATUREFILENAME ++ if [[ $VERSION == *""$RCVERSIONSTRING""* ]]; then ++ BASEDIR=""$BASEDIR${VERSION/%-$RCVERSIONSTRING*}/"" ++ BASEDIR=""$BASEDIR$RCSUBDIR"" ++ else ++ BASEDIR=""$BASEDIR$VERSION/"" ++ fi ++ ++ SIGNATUREFILE=""$BASEDIR$SIGNATUREFILENAME"" ++else ++ BASEDIR=""${SIGNATUREFILE%/*}/"" ++fi ++ ++#first we fetch the file containing the signature ++WGETOUT=$(wget -N ""$BASEDIR$SIGNATUREFILENAME"" 2>&1) ++ ++#and then see if wget completed successfully ++if [ $? -ne 0 ]; then ++ echo ""Error: couldn't fetch signature file. Have you specified the version number in the following format?"" ++ echo ""[bitcoin-]-[rc[0-9]] (example: bitcoin-0.7.1-rc1)"" ++ echo ""wget output:"" ++ echo ""$WGETOUT""|sed 's/^/\t/g' ++ exit 2 ++fi ++ ++#then we check it ++GPGOUT=$(gpg --yes --decrypt --output ""$TMPFILE"" ""$SIGNATUREFILENAME"" 2>&1) ++ ++#return value 0: good signature ++#return value 1: bad signature ++#return value 2: gpg error ++ ++RET=""$?"" ++if [ $RET -ne 0 ]; then ++ if [ $RET -eq 1 ]; then ++ #and notify the user if it's bad ++ echo ""Bad signature."" ++ elif [ $RET -eq 2 ]; then ++ #or if a gpg error has occured ++ echo ""gpg error. Do you have Gavin's code signing key installed?""","0.7.0 is a first-time stable release: it's built off master, not a stable branch. + +I wouldn't suggest touching the user's PGP setup, but verifying without touching it. If GPG really needs to keep keys somewhere, ~/.bitcoin/.gnupg or similar makes sense. + +contrib/gitian-downloader contains PGP keys. There's also a git repository here on GitHub with signatures of multiple developers for most releases which would be better to use than the SHA256SUMS file (which can only have one signature). +",de91ea0c0c2fead60bfe9a531558cbe1c562346e +2106671,1,"Indeed, I just used what was there. Sometimes I have not that wide view/knowlegde you have in the area of coding :).""",2012-11-12 20:21:51,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1479#discussion_r2106671,2012-11-13T07:21:51Z,2012-11-13T07:21:51Z,Diapolo,NONE,src/wallet.h,,571.0,,,31,"@@ -563,6 +567,20 @@ class CWalletTx : public CMerkleTx + return nCreditCached; + } + ++ int64 GetImmatureCredit(bool fUseCache=true) const ++ {","Indeed, I just used what was there. Sometimes I have not that wide view/knowlegde you have in the area of coding :). +",966a0e8cc94f2590521e0a2513e0cea32b5bb005 +775576,0,"Both evaluate to binary all-ones and are equivalent on all architectures with two's complement notation for signed numbers (ie, at least all that windows supports.. and certainly that bitcoin supports).""",2012-05-04 05:29:53,laanwj,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1180#discussion_r775576,2012-05-04T17:29:53Z,2012-05-04T17:29:53Z,laanwj,MEMBER,src/net.cpp,,624.0,,,5,"@@ -621,7 +621,7 @@ void ThreadSocketHandler2(void* parg) + if (nSelect == SOCKET_ERROR) + { + int nErr = WSAGetLastError(); +- if (hSocketMax > -1) ++ if (hSocketMax > (SOCKET) -1)","Both evaluate to binary all-ones and are equivalent on all architectures with two's complement notation for signed numbers (ie, at least all that windows supports.. and certainly that bitcoin supports). +",024fa1cb44b8ec577fef07e7b37a4e5b0501dbea +4119756,0,"zlib 1.2.6 is still available on sourceforge: http://sourceforge.net/projects/libpng/files/zlib/1.2.6/zlib-1.2.6.tar.gz/download same with libpng 1.5.9: http://sourceforge.net/projects/libpng/files/libpng15/older-releases/1.5.9/libpng-1.5.9.tar.gz/downlo""",2013-05-07 06:33:31,laanwj,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2622#discussion_r4119756,2013-05-07T18:33:31Z,2013-05-07T18:33:31Z,laanwj,MEMBER,doc/release-process.txt,,32.0,,,7,"@@ -28,8 +28,8 @@ + wget 'http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.6.tar.gz' -O miniupnpc-1.6.tar.gz + wget 'http://www.openssl.org/source/openssl-1.0.1c.tar.gz' + wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz' +- wget 'http://zlib.net/zlib-1.2.6.tar.gz' +- wget 'ftp://ftp.simplesystems.org/pub/libpng/png/src/libpng-1.5.9.tar.gz' ++ wget 'http://zlib.net/zlib-1.2.8.tar.gz' ++ wget 'http://prdownloads.sourceforge.net/libpng/libpng-1.6.2.tar.gz?download'","zlib 1.2.6 is still available on sourceforge: http://sourceforge.net/projects/libpng/files/zlib/1.2.6/zlib-1.2.6.tar.gz/download +same with libpng 1.5.9: http://sourceforge.net/projects/libpng/files/libpng15/older-releases/1.5.9/libpng-1.5.9.tar.gz/download +",5f479bec525c8dbf12eb431f22577b62b9a9d63d +3794197,0,"a new script must be called before packaging (fancy dmg) and before code sign. """,2013-04-15 02:18:25,jonasschnelli,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2532#discussion_r3794197,2013-04-15T14:18:25Z,2013-04-15T14:18:25Z,jonasschnelli,CONTRIBUTOR,doc/release-process.txt,,83.0,,,4,"@@ -80,6 +80,7 @@ + make + export QTDIR=/opt/local/share/qt4 # needed to find translations/qt_*.qm files + T=$(contrib/qt_translations.py $QTDIR/translations src/qt/locale) ++ python2.7 share/qt/clean_mac_info_plist.py","a new script must be called before packaging (fancy dmg) and before code sign. +",f95279ba79be1c46fe14468269ae53cdb3ac9c24 +3695711,0,"Luke had a pullreq some time ago which introduced this abstraction, yes. I think it's overkill. Also, I want to extend it to transaction hashes too.""",2013-04-08 02:52:46,sipa,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2478#discussion_r3695711,2013-04-08T14:52:46Z,2013-04-08T14:52:46Z,sipa,MEMBER,src/main.h,,198.0,,,4,"@@ -195,11 +195,6 @@ + + + +-static inline std::string BlockHashStr(const uint256& hash)","Luke had a pullreq some time ago which introduced this abstraction, yes. I think it's overkill. Also, I want to extend it to transaction hashes too. +",1c06aa98c63fff02679d446588fad06ae8cd706f +3732049,0,"If we want to give people a choice about how long the hashes are (using a setting in bitcoin.conf), then surely this function would need to be re-introduced again, wouldn't it?""",2013-04-09 23:53:29,rebroad,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2478#discussion_r3732049,2013-04-10T11:53:29Z,2013-04-10T11:53:29Z,rebroad,CONTRIBUTOR,src/main.h,,198.0,,,4,"@@ -195,11 +195,6 @@ + + + +-static inline std::string BlockHashStr(const uint256& hash)","If we want to give people a choice about how long the hashes are (using a setting in bitcoin.conf), then surely this function would need to be re-introduced again, wouldn't it? +",1c06aa98c63fff02679d446588fad06ae8cd706f +3685878,1,"Can you indent these and the 2 below with the above line :)?""",2013-04-06 22:51:43,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2477#discussion_r3685878,2013-04-07T10:51:43Z,2013-04-08T08:37:30Z,Diapolo,NONE,doc/assets-attribution.txt,,3.0,,,4,"@@ -1,5 +1,8 @@ + Icon: src/qt/res/icons/clock*.png, src/qt/res/icons/tx*.png, +- src/qt/res/src/*.svg ++ src/qt/res/src/clock_green.svg, src/qt/res/src/clock1.svg ++ src/qt/res/src/clock2.svg, src/qt/res/src/clock3.svg","Can you indent these and the 2 below with the above line :)? +",a653191f748f56addf0cfa219319cfc5358b962d +1527031,1,"Now I got it yes, my brain told me hey, when SUCKS4 and -proxy, SetLimited(Tor and IPv6), which currently is not the case ^^. But I like the idea, as really no one expects a non-proxy connection, when -proxy was set. If you want me to integrate tha""",2012-09-04 08:05:36,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1781#discussion_r1527031,2012-09-04T20:05:36Z,2012-11-04T16:26:50Z,Diapolo,NONE,src/init.cpp,,,,,1,"@@ -226,9 +226,10 @@ bool static Bind(const CService &addr, bool fError = true) { + "" -dbcache= "" + _(""Set database cache size in megabytes (default: 25)"") + ""\n"" + + "" -dblogsize= "" + _(""Set database disk log size in megabytes (default: 100)"") + ""\n"" + + "" -timeout= "" + _(""Specify connection timeout in milliseconds (default: 5000))"") + ""\n"" + +- "" -proxy= "" + _(""Connect through socks proxy"") + ""\n"" + +- "" -socks= "" + _(""Select the version of socks proxy to use (4-5, default: 5)"") + ""\n"" + +- "" -tor= "" + _(""Use proxy to reach tor hidden services (default: same as -proxy)"") + ""\n"" ++ "" -proxy= "" + _(""Connect through SOCKS proxy"") + ""\n"" + ++ "" -socks= "" + _(""Select SOCKS version for -proxy (4 or 5, default: 5)"") + ""\n"" + ++ "" -proxy6= "" + _(""Use separate SOCKS5 proxy to reach IPv6 peers (default: -proxy if no -socks=4)"") + ""\n"" +","Now I got it yes, my brain told me hey, when SUCKS4 and -proxy, SetLimited(Tor and IPv6), which currently is not the case ^^. But I like the idea, as really no one expects a non-proxy connection, when -proxy was set. If you want me to integrate that change that's good, as it makes sense (even as another special-case). +",d513e73239b03774cf81c32a329f2464824057f7 +1527632,0,"I found out that setting an invalid -proxy leads to not even entering the BOOST_FOREACH loops, as vhListenSocket and vNodes are empty. That means hSocketMax simply keeps the init value of 0, which leads to 10022 spam. I also did some research for the fir""",2012-09-04 08:50:37,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1772#discussion_r1527632,2012-09-04T20:50:37Z,2012-09-04T20:51:59Z,Diapolo,NONE,src/net.cpp,,787.0,,,10,"@@ -781,10 +781,9 @@ void ThreadSocketHandler2(void* parg) + return; + if (nSelect == SOCKET_ERROR) + { +- int nErr = WSAGetLastError(); +- if (hSocketMax != INVALID_SOCKET) ++ if ((hSocketMax != INVALID_SOCKET) && (hSocketMax != (SOCKET)0)) + { +- printf(""socket select error %d\n"", nErr); ++ printf(""socket select error %d\n"", WSAGetLastError()); + for (unsigned int i = 0; i <= hSocketMax; i++)","I found out that setting an invalid -proxy leads to not even entering the BOOST_FOREACH loops, as vhListenSocket and vNodes are empty. That means hSocketMax simply keeps the init value of 0, which leads to 10022 spam. + +I also did some research for the first select()-parameter and found this: + +

The first parameter to select() is the maximum file descriptor that is set in the structs PLUS ONE. That is, if you have 20 file descriptors in the sets, and the maximum value a file descriptor has is 123, then the value passed as the first parameter must be 124.
+ +This makes me think the + 1 before hSocketMax in select() is indeed correct and valid. +",8207857f401bc1a48f863be646c5a508a7cdfe9c +766471,0,"We could define a constant for (unsigned int) -1, as it's a magic marker value we use in many places. """,2012-05-02 17:56:15,laanwj,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1180#discussion_r766471,2012-05-03T05:56:15Z,2012-05-03T05:56:15Z,laanwj,MEMBER,src/main.cpp,,1839.0,,,5,"@@ -1836,7 +1836,7 @@ bool CheckDiskSpace(uint64 nAdditionalBytes) + + FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode) + { +- if (nFile == -1) ++ if ((nFile < 1) || (nFile == (unsigned int) -1))","We could define a constant for (unsigned int) -1, as it's a magic marker value we use in many places. +",024fa1cb44b8ec577fef07e7b37a4e5b0501dbea +364314,0,"Note: sourceforge shows MD5 and SHA1 sums for files (poke the i-in-a-circle next to a file), and SHA-1 is the default for the shasum utility. Seems to me it would be better to sign a SHASUMS that contained BOTH SHA1 and SHA256 checksums. """,2012-01-18 08:32:06,gavinandresen,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/764#discussion_r364314,2012-01-18T19:32:06Z,2012-01-18T19:32:06Z,gavinandresen,CONTRIBUTOR,doc/release-process.txt,,84.0,,,14,"@@ -77,9 +79,9 @@ + Build output expected: + Bitcoin-Qt.dmg + +-* upload source and builds to SourceForge ++* upload builds to SourceForge + +-* create SHA1SUMS for builds, and PGP-sign it ++* create SHA256SUMS for builds, and PGP-sign it","Note: sourceforge shows MD5 and SHA1 sums for files (poke the i-in-a-circle next to a file), and SHA-1 is the default for the shasum utility. + +Seems to me it would be better to sign a SHASUMS that contained BOTH SHA1 and SHA256 checksums. +",9965e1d044a11cbfdb098d57a6a3c7ba477f36f4 +139375,0,"Passphrase"""" was just fine IMHO. We really want users to use a longer sentence instead of just a password. Also, """"Verschlüsselungs-Kennwort zur Dekodierung"""" has too much redundancy.""",2011-09-24 07:18:15,tcatm,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/530#discussion_r139375,2011-09-24T19:18:15Z,2011-09-24T19:18:15Z,lost-tty,NONE,locale/de/LC_MESSAGES/bitcoin.po,,268.0,,,82,"@@ -265,13 +265,13 @@ msgstr ""Passphrase"" + + #: ../../../src/ui.cpp:267 + msgid ""Please supply the current wallet decryption passphrase."" +-msgstr ""Bitte geben Sie die derzeitige Passphrase zur Entschlüsselung der Brieftasche an."" ++msgstr ""Bitte geben Sie das derzeitige Verschlüsselungs-Kennwort zur Dekodierung der Brieftasche an.""","""Passphrase"" was just fine IMHO. We really want users to use a longer sentence instead of just a password. Also, ""Verschlüsselungs-Kennwort zur Dekodierung"" has too much redundancy. +",3449db1bef59fb0deadffd32d9d494815189b6dd +1537620,0,"It is nicer this way, especially if you are stepping through with a debugger.""",2012-09-05 08:11:42,jgarzik,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1786#discussion_r1537620,2012-09-05T20:11:42Z,2012-09-05T20:11:42Z,jgarzik,CONTRIBUTOR,src/net.cpp,,790.0,,,37,"@@ -775,15 +778,16 @@ void ThreadSocketHandler2(void* parg) + } + + vnThreadsRunning[THREAD_SOCKETHANDLER]--; +- int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout); ++ int nSelect = select(have_fds ? hSocketMax + 1 : 0, ++ &fdsetRecv, &fdsetSend, &fdsetError, &timeout); + vnThreadsRunning[THREAD_SOCKETHANDLER]++; + if (fShutdown) + return; + if (nSelect == SOCKET_ERROR) + { +- int nErr = WSAGetLastError(); +- if (hSocketMax != INVALID_SOCKET) ++ if (have_fds) + { ++ int nErr = WSAGetLastError();","It is nicer this way, especially if you are stepping through with a debugger. +",2387944782fa61a3137afda91e9e8105d8cc5ddf +3853387,1,"If you take a look at some other Qt files, you'll see this is already the case in several files, which I also couldn't compile. If you are able to come up with a solution that works, that is fine :).""",2013-04-18 01:40:02,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2538#discussion_r3853387,2013-04-18T13:40:02Z,2013-04-18T13:40:02Z,Diapolo,NONE,src/qt/splashscreen.cpp,,1.0,,,1,"@@ -1,9 +1,10 @@ ++#include ","If you take a look at some other Qt files, you'll see this is already the case in several files, which I also couldn't compile. If you are able to come up with a solution that works, that is fine :). +",4193a647354634326957f5e00d53fc474a36e125 +1120245,0,"I like the first idea, saves a few lines of code and we won't forget to add it (perhaps as another pull or commit for this one?). I can't comment on the Boost.Thread stuff, but as we include or somewhere else use it (the lib is there), why not ... perhap""",2012-07-08 17:06:14,Diapolo,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/1515#discussion_r1120245,2012-07-09T05:06:14Z,2012-07-16T23:53:42Z,Diapolo,NONE,src/net.cpp,,408.0,,,2,"@@ -407,6 +407,9 @@ bool GetMyExternalIP(CNetAddr& ipRet) + + void ThreadGetMyExternalIP(void* parg)","I like the first idea, saves a few lines of code and we won't forget to add it (perhaps as another pull or commit for this one?). + +I can't comment on the Boost.Thread stuff, but as we include or somewhere else use it (the lib is there), why not ... perhaps main devs can comment here. +",36fe96581f343aaae91e34b59c223c8e156f14e3 +2302910,1,"Ok, cool :)""",2012-12-03 20:07:01,laanwj,bitcoin,bitcoin,,https://github.com/bitcoin/bitcoin/pull/2045#discussion_r2302910,2012-12-04T07:07:01Z,2012-12-04T07:07:01Z,laanwj,MEMBER,src/qt/bitcoingui.cpp,,897.0,,,86,"@@ -898,8 +894,12 @@ void BitcoinGUI::backupWallet() + QString filename = QFileDialog::getSaveFileName(this, tr(""Backup Wallet""), saveDir, tr(""Wallet Data (*.dat)"")); + if(!filename.isEmpty()) { + if(!walletModel->backupWallet(filename)) { +- QMessageBox::warning(this, tr(""Backup Failed""), tr(""There was an error trying to save the wallet data to the new location."")); ++ message(tr(""Backup Failed""), tr(""There was an error trying to save the wallet data to the new location.""),","Ok, cool :) +",50ecd7b68970062bfb540798370dbfab6d376086 diff --git a/data/PR inline comments/boto_sentiment_pr_inline_comments_joined.csv b/data/PR inline comments/boto_sentiment_pr_inline_comments_joined.csv new file mode 100644 index 0000000..7de2804 --- /dev/null +++ b/data/PR inline comments/boto_sentiment_pr_inline_comments_joined.csv @@ -0,0 +1,189 @@ +comment_id,polarity,text,created_at_gold,author_login,owner,repo,review_id,html_url,created_at_kaiaulu,updated_at,comment_user_login,author_association,file_path,start_line,line,original_start_line,original_line,position,diff_hunk,body,commit_id +742471,0,"PVS Studio. Also it's free (month license) for opensource projects (http://www.viva64.com/en/b/0092/).""",2012-04-26 12:00:35,evanworley,boto,boto,,https://github.com/boto/boto/pull/727#discussion_r742471,2012-04-27T00:00:35Z,2012-04-27T00:00:35Z,evanworley,CONTRIBUTOR,boto/gs/resumable_upload_handler.py,,406.0,,,34,"@@ -399,11 +397,18 @@ def _attempt_resumable_upload(self, key, fp, file_length, headers, cb, + self._query_server_pos(conn, file_length)) + self.server_has_bytes = server_start + +- # Cannot use incremental md5 calculation if the server already has some of the data. + if server_end: +- self.incremental_md5 = False ++ # If the server already has some of the content, we need to update the md5 with ++ # the bytes that have already been uploaded to ensure we get a complete hash in ++ # the end. ++ print 'Catching up md5 for resumed upload' ++ fp.seek(0) ++ bytes_to_go = server_end + 1 ++ while bytes_to_go: ++ chunk = fp.read(min(key.BufferSize, bytes_to_go)) ++ md5sum.update(chunk) ++ bytes_to_go -= len(chunk) + +- key=key","Cleaned up +",d03726240e0fba8b7366242b360feb5676dfccfe +329404,0,"Hmmm. I don't have an environment at home to test with but I was thinking... why do I have to decode() here??? Shouldn't the object already be in unicode? I remembered thinking about the DeleteMarker and Key objects where they parse xml and pondering the """,2012-01-04 23:47:13,tpodowd,boto,boto,,https://github.com/boto/boto/pull/461#discussion_r329404,2012-01-05T10:47:13Z,2012-01-06T02:46:36Z,tpodowd,CONTRIBUTOR,boto/s3/bucket.py,,523.0,,,66,"@@ -503,15 +509,26 @@ def delete_keys(self, keys, quiet=False, mfa_token=None, headers=None): + key_name = key.name + version_id = key.version_id + else: +- skipped.append(key) ++ if isinstance(key, Prefix): ++ key_name = key.name ++ code = 'PrefixSkipped' # Don't delete Prefix ++ else: ++ key_name = repr(key) # try get a string ++ code = 'InvalidArgument' # other unknown type ++ message = 'Invalid. No delete action taken for this object.' ++ error = Error(key_name, code=code, message=message) ++ result.errors.append(error) + continue +- data += ""%s"" % xml.sax.saxutils.escape(key_name) ++ count += 1 ++ key_name = key_name.decode('utf-8')","Hmmm. I don't have an environment at home to test with but I was thinking... why do I have to decode() here??? Shouldn't the object already be in unicode? I remembered thinking about the DeleteMarker and Key objects where they parse xml and pondering the logic behind the following. + +``` +if name == 'Key': + self.name = value.encode('utf-8') +``` + +I think internally, we should be using unicode keys names. So I think this should be. I'll do some tests with that. + +``` +if name == 'Key': + self.name = value +``` + +That way, I guess we wouldn't need the decode here. +",c7be0020db068420ef4974c1a502c317fbc33947 +1882593,0,"This is just another of the things I noticed and fixed while this pull request was waiting. I don't believe I can create multiple pull requests with the different bits so it got included here. The reason for this change is that the cookie_expiration_pe""",2012-10-18 06:56:04,reversefold,boto,boto,,https://github.com/boto/boto/pull/833#discussion_r1882593,2012-10-18T18:56:04Z,2012-11-27T06:35:23Z,reversefold,CONTRIBUTOR,boto/ec2/elb/__init__.py,,438.0,,,7,"@@ -432,8 +432,8 @@ def create_app_cookie_stickiness_policy(self, name, lb_name, policy_name): + 'PolicyName': policy_name} + return self.get_status('CreateAppCookieStickinessPolicy', params) + +- def create_lb_cookie_stickiness_policy(self, cookie_expiration_period, +- lb_name, policy_name): ++ def create_lb_cookie_stickiness_policy(self, lb_name, policy_name, ++ cookie_expiration_period=None):","This is just another of the things I noticed and fixed while this pull request was waiting. I don't believe I can create multiple pull requests with the different bits so it got included here. + +The reason for this change is that the cookie_expiration_period isn't required as part of these calls. Leaving the value as None (and not sending to the API) allows you to create a stickiness policy with a non-expiring cookie. +",ccfa42f3402c08c79fb8fd5ae0269cb96a58e775 +357720,2,"That's what I get for hand-copying the patch after spending all night on a plane. Thanks for catching that. :-\\""",2012-01-16 17:03:04,gholms,boto,boto,,https://github.com/boto/boto/pull/477#discussion_r357720,2012-01-17T04:03:04Z,2012-01-17T04:03:04Z,gholms,CONTRIBUTOR,boto/jsonresponse.py,,145.0,,,13,"@@ -134,12 +134,14 @@ def get_name(self, name): + def startElement(self, name, attrs, connection): + for lm in self.list_marker: + if name.endswith(lm): +- l = ListElement(self.connection, name, self.item_marker, ++ l = ListElement(self.connection, name, self.list_marker, ++ self.item_marker, + pythonize_name=self.pythonize_name) + setattr(self, self.get_name(name), l) + return l + if name in self.item_marker: + e = Element(self.connection, name, parent=self, ++ self.list_marker, self.item_marker, + pythonize_name=self.pythonize_name)","That's what I get for hand-copying the patch after spending all night on a plane. Thanks for catching that. :-\ +",84fd00b5762c95245cdfca117a7495ba3b06a39a +13980,0,"some debug print statements, I think.""",2011-03-30 12:11:44,garnaat,boto,boto,,https://github.com/boto/boto/pull/122#discussion_r13980,2011-03-31T00:11:44Z,2011-03-31T00:11:44Z,garnaat,MEMBER,boto/ec2/autoscale/group.py,,126.0,,,44,"@@ -106,12 +109,21 @@ class AutoScalingGroup(object): + zones = availability_zones or [] + self.availability_zone = availability_zone + self.availability_zones = ListElement(zones) ++ self.group_arn = group_arn ++ self.health_check_type = health_check_type ++ self.health_check_period = health_check_period ++ self.suspended = suspended ++ self.placement_group = placement_group ++ self.vpc_zone = vpc_zone ++ self.metrics = None + self.instances = None + + def __repr__(self): + return 'AutoScalingGroup:%s' % self.name + + def startElement(self, name, attrs, connection): ++ print '-' *50 ++ print 'Start %s' % name","some debug print statements, I think. +",26660231433d920f53d82e985d7b05310f6868d0 +1878831,0,"Not quite sure why these LB cookie methods are included in this PR. Are they related? The changes will break existing code but if there is a good reason, it may still be the right thing to do. Just need a bit more background.""",2012-10-18 01:57:22,garnaat,boto,boto,,https://github.com/boto/boto/pull/833#discussion_r1878831,2012-10-18T13:57:22Z,2012-11-27T06:35:23Z,garnaat,MEMBER,boto/ec2/elb/__init__.py,,438.0,,,7,"@@ -432,8 +432,8 @@ def create_app_cookie_stickiness_policy(self, name, lb_name, policy_name): + 'PolicyName': policy_name} + return self.get_status('CreateAppCookieStickinessPolicy', params) + +- def create_lb_cookie_stickiness_policy(self, cookie_expiration_period, +- lb_name, policy_name): ++ def create_lb_cookie_stickiness_policy(self, lb_name, policy_name, ++ cookie_expiration_period=None):","Not quite sure why these LB cookie methods are included in this PR. Are they related? The changes will break existing code but if there is a good reason, it may still be the right thing to do. Just need a bit more background. +",ccfa42f3402c08c79fb8fd5ae0269cb96a58e775 +2491018,0,"I think that's reasonable. One of the changes I've added to the provider module was to log where the credentials are coming from, so I went ahead and added log messages for keyring credentials as well. I also added a log message when the keyring module """,2012-12-21 06:52:51,jamesls,boto,boto,,https://github.com/boto/boto/pull/1157#discussion_r2491018,2012-12-21T17:52:51Z,2012-12-21T17:52:51Z,jamesls,MEMBER,boto/provider.py,,251.0,,,6,"@@ -246,6 +246,11 @@ def get_credentials(self, access_key=None, secret_key=None): + self.secret_key = os.environ[secret_key_name.upper()] + elif config.has_option('Credentials', secret_key_name): + self.secret_key = config.get('Credentials', secret_key_name) ++ elif config.has_option('Credentials', 'keyring'): ++ keyring_name = config.get('Credentials', 'keyring') ++ import keyring","I think that's reasonable. One of the changes I've added to the provider module was to log where the credentials are coming from, so I went ahead and added log messages for keyring credentials as well. I also added a log message when the keyring module can't be imported, but still let the ImportError propogate. + +Thanks for the pull request. +",86c0e28ef19e2f3c0f7ffcd649985ec2eed14fe2 +1247543,0,"@leprechaun This should be: ``` BotoConfigLocations.append(os.path.join(os.getcwd(), """".boto"""")) ``` This avoids an invalid path on Windows. Also spaces after or before parenthesis aren't preferred according to PEP8 which I believe @garnaat is trying to""",2012-07-26 07:41:53,jtriley,boto,boto,,https://github.com/boto/boto/pull/885#discussion_r1247543,2012-07-26T19:41:53Z,2012-07-26T19:41:53Z,jtriley,CONTRIBUTOR,boto/pyami/config.py,,46.0,,,13,"@@ -35,12 +35,15 @@ + # This is probably running on App Engine. + expanduser = (lambda x: x) + +-# By default we use two locations for the boto configurations, ++# By default we use three locations for the boto configurations, + # /etc/boto.cfg and ~/.boto (which works on Windows and Unix). ++# os.getcwd() was added so users could have multiple config files ++# without using environment variables + BotoConfigPath = '/etc/boto.cfg' + BotoConfigLocations = [BotoConfigPath] + UserConfigPath = os.path.join(expanduser('~'), '.boto') + BotoConfigLocations.append(UserConfigPath) ++BotoConfigLocations.append( os.getcwd() + ""/.boto"" )","@leprechaun This should be: + +``` +BotoConfigLocations.append(os.path.join(os.getcwd(), "".boto"")) +``` + +This avoids an invalid path on Windows. + +Also spaces after or before parenthesis aren't preferred according to PEP8 which I believe @garnaat is trying to stick with... +",82f46b33874b145abf797a60396e4029c0ca8c09 +1878850,0,"Unfortunately, this will cause SSL certificate verification to fail on all Python versions < 2.7.3. The endpoint we use MUST match the commonName in the SSL certificate since the Python ssl module is unable to find the subjectAlt fields in the certificat""",2012-10-18 01:59:42,garnaat,boto,boto,,https://github.com/boto/boto/pull/833#discussion_r1878850,2012-10-18T13:59:42Z,2012-11-27T06:35:23Z,garnaat,MEMBER,boto/rds/__init__.py,,,,,1,"@@ -79,7 +79,7 @@ def connect_to_region(region_name, **kw_params): + class RDSConnection(AWSQueryConnection): + + DefaultRegionName = 'us-east-1' +- DefaultRegionEndpoint = 'rds.amazonaws.com' ++ DefaultRegionEndpoint = 'rds.us-east-1.amazonaws.com'","Unfortunately, this will cause SSL certificate verification to fail on all Python versions < 2.7.3. The endpoint we use MUST match the commonName in the SSL certificate since the Python ssl module is unable to find the subjectAlt fields in the certificate. +",ccfa42f3402c08c79fb8fd5ae0269cb96a58e775 +5668963,0,"Corrected in SHA: 58a13d7""",2013-08-08 08:26:41,toastdriven,boto,boto,,https://github.com/boto/boto/pull/1660#discussion_r5668963,2013-08-08T20:26:41Z,2013-08-08T20:26:41Z,toastdriven,CONTRIBUTOR,boto/dynamodb2/items.py,,,,,1,"@@ -383,6 +383,17 @@ def partial_save(self): + if not final_data: + return False + ++ # Remove the key(s) if present.","Corrected in SHA: 58a13d7 +",58a13d7104e27bd123bbfd85c4d7294497defb94 +2572998,0,"In the unit tests I wrote to handle _sign_string's three use cases (private key file object, private key file name, private key string), the private key file object test was failing because no data was being read from the file object. The seek(0) fixed th""",2013-01-07 15:35:34,seandst,boto,boto,,https://github.com/boto/boto/pull/1214#discussion_r2572998,2013-01-08T02:35:34Z,2013-01-08T14:13:11Z,tehsmyers,CONTRIBUTOR,boto/cloudfront/distribution.py,,,,,1,"@@ -654,18 +654,17 @@ def _sign_string(message, private_key_file=None, private_key_string=None): + raise ValueError(""Only specify the private_key_file or the private_key_string not both"") + if not private_key_file and not private_key_string: + raise ValueError(""You must specify one of private_key_file or private_key_string"") +- # if private_key_file is a file object read the key string from there ++ # If private_key_file is a file, read its contents. Otherwise, open it and then read it + if isinstance(private_key_file, file): ++ private_key_file.seek(0)","In the unit tests I wrote to handle _sign_string's three use cases (private key file object, private key file name, private key string), the private key file object test was failing because no data was being read from the file object. The seek(0) fixed the problem. I think the test may have been flawed, so I'll take a closer look before submitting the unit tests for this. + +In hindsight, the seek will probably break on file-like objects that don't support seek, so it's probably best to remove it. Any preparation of the passed-in private_key_file can/should be done before the call to create_signed_url. + +Unless there are objections, I'll go ahead and pull out the seek(0) here. +",5ee626a7b47f44a7d7414b2d178858a501708d54 +1969789,0,"Wouldn't it make more sense for this check to happen up a level? It just seems odd that `compute_hashes_from_fileobj` raises an `EmptyArchiveError`. It seems more appropriate for `Vault.upload_archive` to perform the empty file check and raise an except""",2012-10-29 07:20:01,jamesls,boto,boto,,https://github.com/boto/boto/pull/1083#discussion_r1969789,2012-10-29T18:20:01Z,2012-10-29T18:20:01Z,jamesls,MEMBER,boto/glacier/writer.py,,95.0,,,14,"@@ -89,6 +90,10 @@ def compute_hashes_from_fileobj(fileobj, chunk_size=1024 * 1024): + linear_hash.update(chunk) + chunks.append(hashlib.sha256(chunk).digest()) + chunk = fileobj.read(chunk_size) ++ ++ if not chunks: ++ raise EmptyArchiveError()","Wouldn't it make more sense for this check to happen up a level? It just seems odd that `compute_hashes_from_fileobj` raises an `EmptyArchiveError`. It seems more appropriate for `Vault.upload_archive` to perform the empty file check and raise an exception if appropriate +",05915453e3887515338ef9c8a062f78c44430058 +42421,0,"We try not to change the function footprints unless absolutely necessary. Why is it necessary to have both secuirty_group_ids and security_groups?""",2011-06-09 07:38:02,kopertop,boto,boto,,https://github.com/boto/boto/pull/221#discussion_r42421,2011-06-09T19:38:02Z,2011-06-10T06:12:04Z,kopertop,CONTRIBUTOR,boto/ec2/connection.py,,,,,1,"@@ -442,10 +442,10 @@ class EC2Connection(AWSQueryConnection): + [('item', Reservation)], verb='POST') + + def run_instances(self, image_id, min_count=1, max_count=1, +- key_name=None, security_groups=None, +- user_data=None, addressing_type=None, +- instance_type='m1.small', placement=None, +- kernel_id=None, ramdisk_id=None, ++ key_name=None, security_group_ids=None, ++ security_groups=None, user_data=None, ++ addressing_type=None, instance_type='m1.small', ++ placement=None, kernel_id=None, ramdisk_id=None,","We try not to change the function footprints unless absolutely necessary. Why is it necessary to have both secuirty_group_ids and security_groups? +",84f4e05c83ef49f0ebfe4a221839d6a29a5675e6 diff --git a/data/PR inline comments/cakephp_sentiment_pr_inline_comments_joined.csv b/data/PR inline comments/cakephp_sentiment_pr_inline_comments_joined.csv new file mode 100644 index 0000000..f36893d --- /dev/null +++ b/data/PR inline comments/cakephp_sentiment_pr_inline_comments_joined.csv @@ -0,0 +1,4243 @@ +comment_id,polarity,text,created_at_gold,author_login,owner,repo,review_id,html_url,created_at_kaiaulu,updated_at,comment_user_login,author_association,file_path,start_line,line,original_start_line,original_line,position,diff_hunk,text_kaiaulu,polarity_kaiaulu,commit_id +6044242,0,"I had it implemented that way originally. The `rijndael` function uses substrings so I decided to make this the same. Being more strict is an option though.""",8/28/13 7:51,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1568#discussion_r6044242,2013-08-28T19:51:55Z,2013-09-02T01:44:56Z,markstory,MEMBER,lib/Cake/Utility/Security.php,,,,,1,"@@ -289,4 +289,69 @@ protected static function _crypt($password, $salt = false) { + return crypt($password, $salt); + } + ++/** ++ * Encrypt a value using AES-256. ++ * ++ * *Caveat* You cannot properly encrypt/decrypt data with trailing null bytes. ++ * Any trailing null bytes will be removed on decryption due to how PHP pads messages ++ * with nulls prior to encryption. ++ * ++ * @param string $plain The value to encrypt. ++ * @param string $key The 256 bit/32 byte key to use as a cipher key. ++ * @return string Encrypted data. ++ * @throws CakeException On invalid data or key. ++ */ ++ public static function encrypt($plain, $key) { ++ self::_checkKey($key, 'encrypt()'); ++ if (empty($plain)) { ++ throw new CakeException(__d('cake_dev', 'The data to encrypt cannot be empty.')); ++ } ++ $key = substr($key, 0, 32);","I had it implemented that way originally. The `rijndael` function uses substrings so I decided to make this the same. Being more strict is an option though. +",0,13b870d7e183375822eea4ffd66aaacaeec760ff +5949747,0,"This block of code is repeated 3 times in Hash now. Perhaps it would be best extracted into a helper method that does something like: ```php list($token, $conditions) = self::_splitConditions($token); ``` That would address the duplication in the """,8/23/13 1:02,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1549#discussion_r5949747,2013-08-23T13:02:48Z,2013-08-23T23:04:34Z,markstory,MEMBER,lib/Cake/Utility/Hash.php,,149,,,30,"@@ -222,16 +222,36 @@ protected static function _matches(array $data, $selector) { + * @return array The data with $values inserted. + */ + public static function insert(array $data, $path, $values = null) { +- $tokens = explode('.', $path); +- if (strpos($path, '{') === false) { ++ if (strpos($path, '[') === false) { ++ $tokens = explode('.', $path); ++ } else { ++ $tokens = String::tokenize($path, '.', '[', ']'); ++ } ++ ++ if (strpos($path, '{') === false && strpos($path, '[') === false) { + return self::_simpleOp('insert', $data, $tokens, $values); + } + + $token = array_shift($tokens); + $nextPath = implode('.', $tokens); ++ ++ $conditions = false; ++ $position = strpos($token, '['); ++ if ($position !== false) { ++ $conditions = substr($token, $position); ++ $token = substr($token, 0, $position); ++ }","This block of code is repeated 3 times in Hash now. Perhaps it would be best extracted into a helper method that does something like: + +``` php +list($token, $conditions) = self::_splitConditions($token); +``` + +That would address the duplication in the code. +",0,a0014e7a303067bb9c36d438de5a70fe819d22a7 +4288367,0,"This looks good, but makes me think we should have originally added methods like `Security::blowfish($input)` and `Security::matchBlowfish($input, $hashedPassword)` or made a separate utility class for Bcrypt that didn't have as difficult to remember meth""",5/18/13 4:31,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1275#discussion_r4288367,2013-05-18T16:31:19Z,2013-05-26T05:59:44Z,markstory,MEMBER,lib/Cake/Controller/Component/Auth/BlowfishPasswordHasher.php,,44,,,44,"@@ -0,0 +1,58 @@ ++reset();","Resetting validation after it finishes will just break it :( +",0,1224ed595adb3286a6d94ddee2dab18b3a83d7ae +2427846,0,"as @ADmad and I pointed out, you need to respect the coding conventions. too many whitespaces here inside () for example.""",12/14/12 15:18,dereuromark,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1026#discussion_r2427846,2012-12-15T02:18:31Z,2012-12-17T21:25:05Z,dereuromark,MEMBER,lib/Cake/View/Helper/TextHelper.php,,,,,1,"@@ -228,6 +228,29 @@ public function highlight($text, $phrase, $options = array()) { + } + + /** ++ * Formats paragraphs around given text for all line breaks ++ *
added for single line return ++ *

added for double line return ++ * ++ * @param string $text Text ++ * @return string The text with proper

tags ++ * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/text.html#TextHelper::autoParagraph ++ */ ++ public static function autoParagraph($text) { ++ if ( trim($text) !== '' ) {","as @ADmad and I pointed out, you need to respect the coding conventions. too many whitespaces here inside () for example. +",0,03fdd4a14bfed87d35452b5c24c67fdb9f41b6fb +2385747,0,"`return $readyFds > 0` would suffice here. also, never forget the {} for if statements""",12/11/12 11:12,dereuromark,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1017#discussion_r2385747,2012-12-11T22:12:22Z,2012-12-12T17:24:00Z,dereuromark,MEMBER,lib/Cake/Console/ConsoleInput.php,,,,,1,"@@ -48,4 +48,20 @@ public function read() { + return fgets($this->_input); + } + ++/** ++ * Check if data is available on stdin ++ * ++ * @param integer $timeout An optional time to wait for data ++ * @return bool True for data available, false otherwise ++ */ ++ public function data_avail($timeout = 0) { ++ $read_fds = array($this->_input); ++ $ready_fds = stream_select($read_fds, $w = NULL, $e = NULL, $timeout); ++ ++ if($ready_fds > 0) ++ return true; ++ else ++ return false;","`return $readyFds > 0` would suffice here. also, never forget the {} for if statements +",0,d6579a983819a5a9e9209928a241bec48f3e2733 +2217916,1,"yup. i thought of that too but wanted to avoid introducing a new option. but i agree it's cleaner and less hacky. I'll adjust the PR. Thanks.""",11/25/12 15:17,rchavik,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/974#discussion_r2217916,2012-11-26T02:17:09Z,2012-11-28T03:11:43Z,rchavik,MEMBER,lib/Cake/View/Helper/FormHelper.php,,,,,1,"@@ -1094,6 +1071,48 @@ public function input($fieldName, $options = array()) { + unset($options['dateFormat'], $options['timeFormat']); + } + ++ return compact('options', 'label', 'modelKey', 'fieldKey', 'fieldDef', ++ 'divOptions', 'radioOptions', 'error', 'selected', 'dateFormat', ++ 'timeFormat'); ++ } ++ ++/** ++ * Generates a form input element complete with label and wrapper div ++ * ++ * ### Options ++ * ++ * See each field type method for more information. Any options that are part of ++ * $attributes or $options for the different **type** methods can be included in `$options` for input().i ++ * Additionally, any unknown keys that are not in the list below, or part of the selected type's options ++ * will be treated as a regular html attribute for the generated input. ++ * ++ * - `type` - Force the type of widget you want. e.g. `type => 'select'` ++ * - `label` - Either a string label, or an array of options for the label. See FormHelper::label() ++ * - `div` - Either `false` to disable the div, or an array of options for the div. ++ * See HtmlHelper::div() for more options. ++ * - `options` - for widgets that take options e.g. radio, select ++ * - `error` - control the error message that is produced ++ * - `empty` - String or boolean to enable empty select box options. ++ * - `before` - Content to place before the label + input. ++ * - `after` - Content to place after the label + input. ++ * - `between` - Content to place between the label + input. ++ * - `format` - format template for element order. Any element that is not in the array, will not be in the output. ++ * - Default input format order: array('before', 'label', 'between', 'input', 'after', 'error') ++ * - Default checkbox format order: array('before', 'input', 'between', 'label', 'after', 'error') ++ * - Hidden input will not be formatted ++ * - Radio buttons cannot have the order of input and label elements controlled with these settings. ++ * ++ * @param string $fieldName This should be ""Modelname.fieldname"" ++ * @param array $options Each type of input takes different options. ++ * @return string Completed form widget. ++ * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#creating-form-elements ++ */ ++ public function input($fieldName, $options = array()) { ++ if (!isset($options['modelKey'])) { ++ $inputOptions = $this->_inputOptions($fieldName, $options); ++ extract($inputOptions);","yup. i thought of that too but wanted to avoid introducing a new option. +but i agree it's cleaner and less hacky. + +I'll adjust the PR. + +Thanks. +",0,6670997283431c81fc687b79bf2c57e62d9992f4 +1942196,0,"fixed (i will install code sniffer quite soon!)""",10/25/12 3:37,thepeg,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/913#discussion_r1942196,2012-10-25T15:37:54Z,2013-01-20T08:13:46Z,marcopeg,NONE,lib/Cake/Model/Validator/CakeValidationRule.php,,,,,1,"@@ -271,6 +274,17 @@ public function process($field, &$data, &$methods) { + $this->_valid = call_user_func_array($methods[$rule], $this->_ruleParams); + } elseif (class_exists('Validation') && method_exists('Validation', $this->_rule)) { + $this->_valid = call_user_func_array(array('Validation', $this->_rule), $this->_ruleParams); ++ } elseif (strpos($this->_rule, '::')) { ++ list($plugin, $class) = pluginSplit($this->_rule); ++ list($className,$method) = explode('::', $class); ++ $location = 'Model/Validation'; ++ if ( $plugin ) $location = $plugin . '.' . $location;","fixed (i will install code sniffer quite soon!) +",0,b2cbeeeb501285431bdc7fb2a5b37f260b792261 +1616452,0,"it is for adding fields to a query or to the whitelist?""",9/16/12 19:45,lorenzo,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/851#discussion_r1616452,2012-09-17T07:45:13Z,2012-11-02T09:54:30Z,lorenzo,MEMBER,lib/Cake/Model/Model.php,,,,,1,"@@ -2299,6 +2302,29 @@ public function saveAssociated($data = null, $options = array()) { + } + + /** ++ * Helper method for saveAll() and friends, to add foreign key to fieldlist ++ * ++ * @param string $key fieldname to be added to list ++ * @param array $options ++ * @return array $options ++ */ ++ public function addToFieldList($key, $options) {","it is for adding fields to a query or to the whitelist? +",0,7007dba0eb836f852aaca95fada103bc4ba993a9 +1518476,2,"Ah, true. I forgot about that. Browsers... :(""",9/3/12 9:02,jrbasso,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/811#discussion_r1518476,2012-09-03T21:02:57Z,2012-09-03T21:02:57Z,jrbasso,MEMBER,lib/Cake/View/Helper/FormHelper.php,,1614,,,24,"@@ -1607,7 +1612,7 @@ public function postLink($title, $url = null, $options = array(), $confirmMessag + $formName = uniqid('post_'); + $formUrl = $this->url($url); + $out = $this->Html->useTag('form', $formUrl, array('name' => $formName, 'id' => $formName, 'style' => 'display:none;', 'method' => 'post'));","Ah, true. I forgot about that. Browsers... :( +",0,fca98e39f9041c1aee915968e0523dfc83e0c2c8 +1221562,0,"Exceptions should include a useful description based on what the failure is. Perhaps 'Invalid encryption scheme chosen'.""",7/23/12 13:29,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/734#discussion_r1221562,2012-07-24T01:29:22Z,2012-07-25T18:21:05Z,markstory,MEMBER,lib/Cake/Network/CakeSocket.php,,,,,1,"@@ -277,4 +298,34 @@ public function reset($state = null) { + return true; + } + +-} ++/** ++ * Encrypts current stream socket, using one of the defined encryption methods ++ * ++ * @param string $type can be one of 'ssl2', 'ssl3', 'ssl23' or 'tls' ++ * @param string $clientOrServer can be one of 'client', 'server'. Default is 'client' ++ * @param boolean $enable enable or disable encryption. Default is true (enable) ++ * @return boolean True on success ++ * @throws SocketException ++ * @see stream_socket_enable_crypto ++ */ ++ public function enableCrypto($type, $clientOrServer = 'client', $enable = true) { ++ if (!array_key_exists($type . '_' . $clientOrServer, $this->_encryptMethods)) { ++ throw new InvalidArgumentException();","Exceptions should include a useful description based on what the failure is. Perhaps 'Invalid encryption scheme chosen'. +",0,7418be04d3fd24bd7cef09527bd40e55783c28c6 +157669,1,"lol, I left that variable in there and forgot about it :P""",10/6/11 2:08,lorenzo,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/229#discussion_r157669,2011-10-06T14:08:38Z,2011-10-06T14:08:38Z,lorenzo,MEMBER,lib/Cake/Model/Datasource/Database/Postgres.php,,784,,,16,"@@ -781,7 +778,12 @@ class Postgres extends DboSource { + * @return string The database encoding + */ + public function getEncoding() { +- $cosa = $this->_execute('SHOW client_encoding')->fetch();","lol, I left that variable in there and forgot about it :P +",0,ce8ece85aad66f2ad2c38614cd6deba173d43c21 +6432269,0,"sprintf is not necessary here.""",9/18/13 0:59,dereuromark,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1654#discussion_r6432269,2013-09-18T12:59:49Z,2013-10-04T04:05:07Z,dereuromark,MEMBER,lib/Cake/Cache/Engine/MemcachedEngine.php,,,,,1,"@@ -113,14 +127,41 @@ public function init($settings = array()) { + /** + * Settings the memcached instance + * ++ * @throws CacheException when the Memcached extension is not built with the desired serializer engine + */ + protected function _setOptions() { + $this->_Memcached->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true); + +- if (Memcached::HAVE_IGBINARY) { +- $this->_Memcached->setOption(Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_IGBINARY); ++ if (!array_key_exists($this->settings['serializer'], self::$serializer)) { ++ throw new CacheException( ++ __d('cake_dev', sprintf('%s is not a valid serializer engine for Memcached', $this->settings['serializer']))","sprintf is not necessary here. +",0,5d30cb15591af89b33fcbb61c10e4b96452f4ff6 +851797,0,"This is not very readable plus has unnecessary merge with empty array. Better to replace with this: ```php if ($merge) { $this->_inputDefaults = array_merge($this->_inputDefaults, $defaults); } else { $this->_inputDefaults = $defaults; } ```""",5/20/12 19:52,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/659#discussion_r851797,2012-05-21T07:52:51Z,2012-05-21T07:52:51Z,ADmad,MEMBER,lib/Cake/View/Helper/FormHelper.php,,2595,,,22,"@@ -2583,4 +2583,18 @@ protected function _initInputField($field, $options = array()) { + return $result; + } + ++/** ++ * Set/Get inputDefaults for form elements ++ * ++ * @param array $defaults New default values ++ * @param boolean Merge with current defaults ++ * @return array inputDefaults ++ */ ++ public function inputDefaults($defaults = null, $merge = false) { ++ if (!is_null($defaults)) { ++ $this->_inputDefaults = array_merge($merge ? $this->_inputDefaults : array(), (array)$defaults);","This is not very readable plus has unnecessary merge with empty array. Better to replace with this: + +``` php +if ($merge) { + $this->_inputDefaults = array_merge($this->_inputDefaults, $defaults); +} else { + $this->_inputDefaults = $defaults; +} +``` +",0,57ad5e2573198781deb1586242f62a5b62fe26f9 +4976178,2,"This is going to end poorly. I don't like overloading conditions like this, it will break eventually for someone somewhere.""",7/1/13 13:23,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1392#discussion_r4976178,2013-07-02T01:23:40Z,2013-07-11T12:35:45Z,markstory,MEMBER,lib/Cake/Model/Datasource/Database/Mysql.php,,353,,,5,"@@ -349,6 +349,12 @@ public function describe($model) { + * @return array + */ + public function update(Model $model, $fields = array(), $values = null, $conditions = null) { ++ $query = array('joins' => array()); ++ if (isset($conditions['joins'])) {","This is going to end poorly. I don't like overloading conditions like this, it will break eventually for someone somewhere. +",0,096f5f13eedd763c81e186d024110e32e3e01afd +6052285,0,"Do you mean run the key through pbkdf2 before using it as the key on the AES-256 stage?""",8/28/13 15:22,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1568#discussion_r6052285,2013-08-29T03:22:08Z,2013-09-02T01:44:56Z,markstory,MEMBER,lib/Cake/Utility/Security.php,,,,,1,"@@ -289,4 +289,69 @@ protected static function _crypt($password, $salt = false) { + return crypt($password, $salt); + } + ++/** ++ * Encrypt a value using AES-256. ++ * ++ * *Caveat* You cannot properly encrypt/decrypt data with trailing null bytes. ++ * Any trailing null bytes will be removed on decryption due to how PHP pads messages ++ * with nulls prior to encryption. ++ * ++ * @param string $plain The value to encrypt. ++ * @param string $key The 256 bit/32 byte key to use as a cipher key. ++ * @return string Encrypted data. ++ * @throws CakeException On invalid data or key. ++ */ ++ public static function encrypt($plain, $key) { ++ self::_checkKey($key, 'encrypt()'); ++ if (empty($plain)) { ++ throw new CakeException(__d('cake_dev', 'The data to encrypt cannot be empty.')); ++ } ++ $key = substr($key, 0, 32);","Do you mean run the key through pbkdf2 before using it as the key on the AES-256 stage? +",0,13b870d7e183375822eea4ffd66aaacaeec760ff +5181780,1,"Models is fine, they can be isolated, and are easy to talk to directly though the class registry anyway If a normal request has the same event manager for everything but models, then I'm a happy man for a crud plugin perspective :)""",7/14/13 1:22,jippi,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1418#discussion_r5181780,2013-07-14T13:22:44Z,2013-07-27T21:17:13Z,jippi,CONTRIBUTOR,lib/Cake/Controller/ComponentCollection.php,,55,,,71,"@@ -39,20 +41,23 @@ class ComponentCollection extends ObjectCollection implements EventListener { + protected $_Controller = null; + + /** +- * Initializes all the Components for a controller. +- * Attaches a reference of each component to the Controller. ++ * The event manager to bind components to. + * +- * @param Controller $Controller Controller to initialize components for. +- * @return void ++ * @var Cake\Event\EventManager + */ +- public function init(Controller $Controller) { +- if (empty($Controller->components)) { +- return; +- } +- $this->_Controller = $Controller; +- $components = static::normalizeObjectArray($Controller->components); +- foreach ($components as $name => $properties) { +- $Controller->{$name} = $this->load($properties['class'], $properties['settings']); ++ protected $_eventManager = null; ++ ++/** ++ * Constructor. ++ * ++ * @param Cake\Controller\Controller $Controller ++ */ ++ public function __construct(Controller $Controller = null) {","Models is fine, they can be isolated, and are easy to talk to directly though the class registry anyway + +If a normal request has the same event manager for everything but models, then I'm a happy man for a crud plugin perspective :) +",0,c8f6c84285080bfc9020401522b01bb7d50777ab +4604911,2,"nooo, why you hate on Wooohoo ! :(""",6/9/13 8:21,jippi,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1342#discussion_r4604911,2013-06-09T20:21:09Z,2013-06-09T20:21:09Z,jippi,CONTRIBUTOR,lib/Cake/Model/Datasource/DboSource.php,,1330,,,4,"@@ -1327,7 +1327,7 @@ public function queryAssociation(Model $model, &$linkModel, $type, $association, + } + + /** +- * A more efficient way to fetch associations. Woohoo!","nooo, why you hate on Wooohoo ! :( +",0,42777b7809061116a9162cb0f51398999f5bc826 +4394619,0,"I was thinking the upgrade shell might be better as well. Munging the fixtures might be simpler in terms of long term maintainability and correctness. Would updating a the upgrade shell to include a munger, and issuing warnings/exceptions when old styl""",5/26/13 3:52,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1303#discussion_r4394619,2013-05-26T15:52:40Z,2013-05-29T02:13:15Z,markstory,MEMBER,lib/Cake/Test/Fixture/PostFixture.php,,,,,1,"@@ -41,13 +41,16 @@ class PostFixture extends TestFixture { + * @var array + */ + public $fields = array( +- 'id' => array('type' => 'integer', 'key' => 'primary'), ++ 'id' => array('type' => 'integer'), + 'author_id' => array('type' => 'integer', 'null' => false), + 'title' => array('type' => 'string', 'null' => false), + 'body' => 'text', + 'published' => array('type' => 'string', 'length' => 1, 'default' => 'N'), + 'created' => 'datetime', +- 'updated' => 'datetime' ++ 'updated' => 'datetime', ++ 'constraints' => [","I was thinking the upgrade shell might be better as well. Munging the fixtures might be simpler in terms of long term maintainability and correctness. + +Would updating a the upgrade shell to include a munger, and issuing warnings/exceptions when old style fixtures are found sound reasonable? +",0,2b90e7dbc75cccae5f7b1fc76eba57bf6fcbe049 +2011137,0,"Extra space after `array(`""",11/1/12 11:15,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/913#discussion_r2011137,2012-11-01T22:15:03Z,2013-01-20T08:13:46Z,ADmad,MEMBER,lib/Cake/Test/test_app/Controller/CustomValidationObjectController.php,,,,,1,"@@ -0,0 +1,28 @@ ++ array(","Extra space after `array(` +",0,b2cbeeeb501285431bdc7fb2a5b37f260b792261 +1723748,2,"Oh that is a bit silly.""",9/29/12 6:36,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/875#discussion_r1723748,2012-09-29T18:36:55Z,2012-12-10T10:10:06Z,markstory,MEMBER,lib/Cake/Test/Case/View/Helper/FormHelperTest.php,,6120,,,5,"@@ -5966,7 +5966,7 @@ public function testTextAreaWithStupidCharacters() { + 'label' => 'Current Text', 'value' => ""GREAT®"", 'rows' => '15', 'cols' => '75' + )); + $expected = array( +- 'div' => array('class' => 'input text'), ++ 'div' => array('class' => 'input textarea'),","Oh that is a bit silly. +",0,2d908885c86de68f0e0c4cbfd88bce811d23aa54 +1624729,0,"But isn't `fieldList` a copy of the whitelist? I think that is what @lorenzo and I are trying to get at. Perhaps this doesn't need to be a public method? It is just a helper method after all.""",9/17/12 12:24,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/851#discussion_r1624729,2012-09-18T00:24:15Z,2012-11-02T09:54:30Z,markstory,MEMBER,lib/Cake/Model/Model.php,,,,,1,"@@ -2299,6 +2302,29 @@ public function saveAssociated($data = null, $options = array()) { + } + + /** ++ * Helper method for saveAll() and friends, to add foreign key to fieldlist ++ * ++ * @param string $key fieldname to be added to list ++ * @param array $options ++ * @return array $options ++ */ ++ public function addToFieldList($key, $options) {","But isn't `fieldList` a copy of the whitelist? I think that is what @lorenzo and I are trying to get at. Perhaps this doesn't need to be a public method? It is just a helper method after all. +",0,7007dba0eb836f852aaca95fada103bc4ba993a9 +1231261,0,"Same about the translation.""",7/24/12 12:25,jrbasso,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/734#discussion_r1231261,2012-07-25T00:25:55Z,2012-07-25T18:21:05Z,jrbasso,MEMBER,lib/Cake/Network/CakeSocket.php,,,,,1,"@@ -277,4 +298,34 @@ public function reset($state = null) { + return true; + } + +-} ++/** ++ * Encrypts current stream socket, using one of the defined encryption methods ++ * ++ * @param string $type can be one of 'ssl2', 'ssl3', 'ssl23' or 'tls' ++ * @param string $clientOrServer can be one of 'client', 'server'. Default is 'client' ++ * @param boolean $enable enable or disable encryption. Default is true (enable) ++ * @return boolean True on success ++ * @throws SocketException ++ * @see stream_socket_enable_crypto ++ */ ++ public function enableCrypto($type, $clientOrServer = 'client', $enable = true) { ++ if (!array_key_exists($type . '_' . $clientOrServer, $this->_encryptMethods)) { ++ throw new InvalidArgumentException(__('Invalid encryption scheme chosen')); ++ } ++ $enableCryptoResult = false; ++ try { ++ $enableCryptoResult = stream_socket_enable_crypto($this->connection, $enable, $this->_encryptMethods[$type . '_' . $clientOrServer]); ++ } catch (Exception $e) { ++ $this->setLastError(null, $e->getMessage()); ++ throw new SocketException($e->getMessage()); ++ } ++ if ($enableCryptoResult === true) { ++ $this->encrypted = $enable; ++ return true; ++ } else { ++ $errorMessage = __('Unable to perform enableCrypto operation on CakeSocket');","Same about the translation. +",0,7418be04d3fd24bd7cef09527bd40e55783c28c6 +2561154,0,"I guess it should. I was more concerned about the hostnames as sharing cookies between domains is going to cause problems. I forgot about path based cookies though. Both Client::_storeCookies() & Client::_addCookies() will need to be updated.""",1/6/13 14:03,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1057#discussion_r2561154,2013-01-07T01:03:47Z,2013-01-24T02:45:59Z,markstory,MEMBER,lib/Cake/Network/Http/Client.php,,,,,1,"@@ -0,0 +1,515 @@ ++get('/users', [], ['type' => 'json']);` ++ * ++ * The `type` option sets both the `Content-Type` and `Accept` header, to ++ * the same mime type. When using `type` you can use either a full mime ++ * type or an alias. If you need different types in the Accept and Content-Type ++ * headers you should set them manually and not use `type` ++ * ++ * ### Using authentication ++ * ++ * By using the `auth` key you can use authentication. The type sub option ++ * can be used to specify which authentication strategy you want to use. ++ * CakePHP comes with a few built-in strategies: ++ * ++ * - Basic ++ * - Digest ++ * - Oauth ++ * ++ * ### Using proxies ++ * ++ * By using the `proxy` key you can set authentication credentials for ++ * a proxy if you need to use one.. The type sub option can be used to ++ * specify which authentication strategy you want to use. ++ * CakePHP comes with built-in support for basic authentication. ++ * ++ */ ++class Client { ++ ++/** ++ * Stored configuration for the client. ++ * ++ * @var array ++ */ ++ protected $_config = [ ++ 'host' => null, ++ 'port' => null, ++ 'scheme' => 'http', ++ 'timeout' => 30, ++ 'ssl_verify_peer' => true, ++ 'ssl_verify_depth' => 5, ++ 'ssl_verify_host' => true, ++ 'redirect' => false, ++ ]; ++ ++/** ++ * List of cookies from responses made with this client. ++ * ++ * Cookies are indexed by the cookie's domain or ++ * request host name. ++ * ++ * @var array ++ */ ++ protected $_cookies = []; ++ ++/** ++ * Adapter for sending requests. Defaults to ++ * Cake\Network\Http\Stream ++ * ++ * @var Cake\Network\Http\Stream ++ */ ++ protected $_adapter; ++ ++/** ++ * Create a new HTTP Client. ++ * ++ * ### Config options ++ * ++ * You can set the following options when creating a client: ++ * ++ * - host - The hostname to do requests on. ++ * - port - The port to use. ++ * - scheme - The default scheme/protocol to use. Defaults to http. ++ * - timeout - The timeout in seconds. Defaults to 30 ++ * - ssl_verify_peer - Whether or not SSL certificates should be validated. ++ * Defaults to true. ++ * - ssl_verify_depth - The maximum certificate chain depth to travers. ++ * Defaults to 5. ++ * - ssl_verify_host - Verify that the certificate and hostname match. ++ * Defaults to true. ++ * - redirect - Number of redirects to follow. Defaults to false. ++ * ++ * @param array $config Config options for scoped clients. ++ */ ++ public function __construct($config = []) { ++ $adapter = 'Cake\Network\Http\Adapter\Stream'; ++ if (isset($config['adapter'])) { ++ $adapter = $config['adapter']; ++ unset($config['adapter']); ++ } ++ $this->config($config); ++ ++ if (is_string($adapter)) { ++ $adapter = new $adapter(); ++ } ++ $this->_adapter = $adapter; ++ } ++ ++/** ++ * Get or set additional config options. ++ * ++ * Setting config will use Hash::merge() for appending into ++ * the existing configuration. ++ * ++ * @param array|null $config Configuration options. null to get. ++ * @return this|array ++ */ ++ public function config($config = null) { ++ if ($config === null) { ++ return $this->_config; ++ } ++ $this->_config = Hash::merge($this->_config, $config); ++ return $this; ++ } ++ ++/** ++ * Get the cookies stored in the Client. ++ * ++ * @return array ++ */ ++ public function cookies() { ++ return $this->_cookies; ++ } ++ ++/** ++ * Do a GET request. ++ * ++ * The $data argument supports a special `_content` key ++ * for providing a request body in a GET request. This is ++ * generally not used but services like ElasticSearch use ++ * this feature. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The query data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function get($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $body = []; ++ if (isset($data['_content'])) { ++ $body = $data['_content']; ++ unset($data['_content']); ++ } ++ $url = $this->buildUrl($url, $data, $options); ++ return $this->_doRequest( ++ Request::METHOD_GET, ++ $url, ++ $body, ++ $options ++ ); ++ } ++ ++/** ++ * Do a POST request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The post data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function post($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_POST, $url, $data, $options); ++ } ++ ++/** ++ * Do a PUT request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The request data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function put($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_PUT, $url, $data, $options); ++ } ++ ++/** ++ * Do a PATCH request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The request data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function patch($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_PATCH, $url, $data, $options); ++ } ++ ++/** ++ * Do a DELETE request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The request data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function delete($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_DELETE, $url, $data, $options); ++ } ++ ++/** ++ * Helper method for doing non-GET requests. ++ * ++ * @param string $method HTTP method. ++ * @param string $url URL to request. ++ */ ++ protected function _doRequest($method, $url, $data, $options) { ++ $request = $this->_createRequest( ++ $method, ++ $url, ++ $data, ++ $options ++ ); ++ return $this->send($request, $options); ++ } ++ ++/** ++ * Does a recursive merge of the parameter with the scope config. ++ * ++ * @param array $options Options to merge. ++ * @return array Options merged with set config. ++ */ ++ protected function _mergeOptions($options) { ++ return Hash::merge($this->_config, $options); ++ } ++ ++/** ++ * Send a request. ++ * ++ * Used internally by other methods, but can also be used to send ++ * handcrafted Request objects. ++ * ++ * @param Cake\Network\Http\Request $request The request to send. ++ * @param array $options Additional options to use. ++ * @return Cake\Network\Http\Response ++ */ ++ public function send(Request $request, $options = []) { ++ $responses = $this->_adapter->send($request, $options); ++ $host = parse_url($request->url(), PHP_URL_HOST); ++ foreach ($responses as $response) { ++ $this->_storeCookies($response, $host); ++ } ++ return array_pop($responses); ++ } ++ ++/** ++ * Store cookies in a response to be used in future requests. ++ * ++ * Non-expired cookies will be stored for use in future requests ++ * made with the same Client instance. Cookies are not saved ++ * between instances. ++ * ++ * @param Response $response The response to read cookies from ++ * @param string $host The request host, used for getting host names ++ * in case the cookies didn't set a domain. ++ * @return void ++ */ ++ protected function _storeCookies(Response $response, $host) {","I guess it should. I was more concerned about the hostnames as sharing cookies between domains is going to cause problems. I forgot about path based cookies though. Both Client::_storeCookies() & Client::_addCookies() will need to be updated. +",0,c0865001dc9b44d763aba9eaa00720fa4e485ddc +2628259,0,"@markstory To follow the [RFC 2109](http://www.ietf.org/rfc/rfc2109.txt) (section 4.3.1) the path should be the base path of the requested URL when not specified. > Defaults to the path of the request URL that generated the > Set-Cookie response, up t""",1/12/13 13:23,jrbasso,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1057#discussion_r2628259,2013-01-13T00:23:22Z,2013-01-24T02:45:59Z,jrbasso,MEMBER,lib/Cake/Network/Http/Client.php,,,,,1,"@@ -0,0 +1,527 @@ ++get('/users', [], ['type' => 'json']);` ++ * ++ * The `type` option sets both the `Content-Type` and `Accept` header, to ++ * the same mime type. When using `type` you can use either a full mime ++ * type or an alias. If you need different types in the Accept and Content-Type ++ * headers you should set them manually and not use `type` ++ * ++ * ### Using authentication ++ * ++ * By using the `auth` key you can use authentication. The type sub option ++ * can be used to specify which authentication strategy you want to use. ++ * CakePHP comes with a few built-in strategies: ++ * ++ * - Basic ++ * - Digest ++ * - Oauth ++ * ++ * ### Using proxies ++ * ++ * By using the `proxy` key you can set authentication credentials for ++ * a proxy if you need to use one.. The type sub option can be used to ++ * specify which authentication strategy you want to use. ++ * CakePHP comes with built-in support for basic authentication. ++ * ++ */ ++class Client { ++ ++/** ++ * Stored configuration for the client. ++ * ++ * @var array ++ */ ++ protected $_config = [ ++ 'host' => null, ++ 'port' => null, ++ 'scheme' => 'http', ++ 'timeout' => 30, ++ 'ssl_verify_peer' => true, ++ 'ssl_verify_depth' => 5, ++ 'ssl_verify_host' => true, ++ 'redirect' => false, ++ ]; ++ ++/** ++ * List of cookies from responses made with this client. ++ * ++ * Cookies are indexed by the cookie's domain or ++ * request host name. ++ * ++ * @var array ++ */ ++ protected $_cookies = []; ++ ++/** ++ * Adapter for sending requests. Defaults to ++ * Cake\Network\Http\Stream ++ * ++ * @var Cake\Network\Http\Stream ++ */ ++ protected $_adapter; ++ ++/** ++ * Create a new HTTP Client. ++ * ++ * ### Config options ++ * ++ * You can set the following options when creating a client: ++ * ++ * - host - The hostname to do requests on. ++ * - port - The port to use. ++ * - scheme - The default scheme/protocol to use. Defaults to http. ++ * - timeout - The timeout in seconds. Defaults to 30 ++ * - ssl_verify_peer - Whether or not SSL certificates should be validated. ++ * Defaults to true. ++ * - ssl_verify_depth - The maximum certificate chain depth to travers. ++ * Defaults to 5. ++ * - ssl_verify_host - Verify that the certificate and hostname match. ++ * Defaults to true. ++ * - redirect - Number of redirects to follow. Defaults to false. ++ * ++ * @param array $config Config options for scoped clients. ++ */ ++ public function __construct($config = []) { ++ $adapter = 'Cake\Network\Http\Adapter\Stream'; ++ if (isset($config['adapter'])) { ++ $adapter = $config['adapter']; ++ unset($config['adapter']); ++ } ++ $this->config($config); ++ ++ if (is_string($adapter)) { ++ $adapter = new $adapter(); ++ } ++ $this->_adapter = $adapter; ++ } ++ ++/** ++ * Get or set additional config options. ++ * ++ * Setting config will use Hash::merge() for appending into ++ * the existing configuration. ++ * ++ * @param array|null $config Configuration options. null to get. ++ * @return this|array ++ */ ++ public function config($config = null) { ++ if ($config === null) { ++ return $this->_config; ++ } ++ $this->_config = Hash::merge($this->_config, $config); ++ return $this; ++ } ++ ++/** ++ * Get the cookies stored in the Client. ++ * ++ * Returns an array of cookie data arrays. ++ * ++ * @return array ++ */ ++ public function cookies() { ++ return $this->_cookies; ++ } ++ ++/** ++ * Do a GET request. ++ * ++ * The $data argument supports a special `_content` key ++ * for providing a request body in a GET request. This is ++ * generally not used but services like ElasticSearch use ++ * this feature. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The query data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function get($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $body = []; ++ if (isset($data['_content'])) { ++ $body = $data['_content']; ++ unset($data['_content']); ++ } ++ $url = $this->buildUrl($url, $data, $options); ++ return $this->_doRequest( ++ Request::METHOD_GET, ++ $url, ++ $body, ++ $options ++ ); ++ } ++ ++/** ++ * Do a POST request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The post data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function post($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_POST, $url, $data, $options); ++ } ++ ++/** ++ * Do a PUT request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The request data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function put($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_PUT, $url, $data, $options); ++ } ++ ++/** ++ * Do a PATCH request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The request data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function patch($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_PATCH, $url, $data, $options); ++ } ++ ++/** ++ * Do a DELETE request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The request data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function delete($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_DELETE, $url, $data, $options); ++ } ++ ++/** ++ * Helper method for doing non-GET requests. ++ * ++ * @param string $method HTTP method. ++ * @param string $url URL to request. ++ */ ++ protected function _doRequest($method, $url, $data, $options) { ++ $request = $this->_createRequest( ++ $method, ++ $url, ++ $data, ++ $options ++ ); ++ return $this->send($request, $options); ++ } ++ ++/** ++ * Does a recursive merge of the parameter with the scope config. ++ * ++ * @param array $options Options to merge. ++ * @return array Options merged with set config. ++ */ ++ protected function _mergeOptions($options) { ++ return Hash::merge($this->_config, $options); ++ } ++ ++/** ++ * Send a request. ++ * ++ * Used internally by other methods, but can also be used to send ++ * handcrafted Request objects. ++ * ++ * @param Cake\Network\Http\Request $request The request to send. ++ * @param array $options Additional options to use. ++ * @return Cake\Network\Http\Response ++ */ ++ public function send(Request $request, $options = []) { ++ $responses = $this->_adapter->send($request, $options); ++ $host = parse_url($request->url(), PHP_URL_HOST); ++ foreach ($responses as $response) { ++ $this->_storeCookies($response, $host); ++ } ++ return array_pop($responses); ++ } ++ ++/** ++ * Store cookies in a response to be used in future requests. ++ * ++ * Non-expired cookies will be stored for use in future requests ++ * made with the same Client instance. Cookies are not saved ++ * between instances. ++ * ++ * @param Response $response The response to read cookies from ++ * @param string $host The request host, used for getting host names ++ * in case the cookies didn't set a domain. ++ * @return void ++ */ ++ protected function _storeCookies(Response $response, $host) { ++ $cookies = $response->cookies(); ++ foreach ($cookies as $name => $cookie) { ++ $expires = isset($cookie['expires']) ? $cookie['expires'] : false; ++ if ($expires) { ++ $expires = \DateTime::createFromFormat('D, j-M-Y H:i:s e', $expires); ++ } ++ if ($expires && $expires->getTimestamp() <= time()) { ++ continue; ++ } ++ if (empty($cookie['domain'])) { ++ $cookie['domain'] = $host; ++ } ++ $cookie['domain'] = trim($cookie['domain'], '.'); ++ if (empty($cookie['path'])) { ++ $cookie['path'] = '/';","@markstory To follow the [RFC 2109](http://www.ietf.org/rfc/rfc2109.txt) (section 4.3.1) the path should be the base path of the requested URL when not specified. + +> Defaults to the path of the request URL that generated the +> Set-Cookie response, up to, but not including, the +> right-most /. +",0,c0865001dc9b44d763aba9eaa00720fa4e485ddc +6224808,0,"@markstory Agree about the usage and expectations of support of those options...""",9/7/13 2:25,ravage84,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1606#discussion_r6224808,2013-09-07T14:25:24Z,2013-09-09T14:49:11Z,ravage84,MEMBER,App/App/Config/bootstrap.php,,,,,1,"@@ -14,9 +14,11 @@ + */ + namespace App\Config; + +-if (file_exists(dirname(__DIR__) . 'vendor/autoload.php')) { +- require dirname(__DIR__) . 'vendor/autoload.php'; ++if (!file_exists(dirname(dirname(__DIR__)) . '/vendor/autoload.php')) { ++ die('Could not find vendor/autoload.php. You need to install dependencies with `php composer.phar install` first.');","@markstory Agree about the usage and expectations of support of those options... +",0,5bdb78603590331da86f3aea10ab718e0a29a0b9 +6060638,0,"Another possible good idea is to add an hmac to detect tampering. I know zf2 does this as do a few other implementations I've seen.""",8/29/13 1:52,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1568#discussion_r6060638,2013-08-29T13:52:47Z,2013-09-02T01:44:56Z,markstory,MEMBER,lib/Cake/Utility/Security.php,,,,,1,"@@ -289,4 +289,69 @@ protected static function _crypt($password, $salt = false) { + return crypt($password, $salt); + } + ++/** ++ * Encrypt a value using AES-256. ++ * ++ * *Caveat* You cannot properly encrypt/decrypt data with trailing null bytes. ++ * Any trailing null bytes will be removed on decryption due to how PHP pads messages ++ * with nulls prior to encryption. ++ * ++ * @param string $plain The value to encrypt. ++ * @param string $key The 256 bit/32 byte key to use as a cipher key. ++ * @return string Encrypted data. ++ * @throws CakeException On invalid data or key. ++ */ ++ public static function encrypt($plain, $key) { ++ self::_checkKey($key, 'encrypt()'); ++ if (empty($plain)) { ++ throw new CakeException(__d('cake_dev', 'The data to encrypt cannot be empty.')); ++ } ++ $key = substr($key, 0, 32);","Another possible good idea is to add an hmac to detect tampering. I know zf2 does this as do a few other implementations I've seen. +",0,13b870d7e183375822eea4ffd66aaacaeec760ff +5912764,2,"That was the reason I started to extract stuff into a Trait, found out the hard way it was not possible :(""",8/21/13 11:27,lorenzo,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1544#discussion_r5912764,2013-08-21T23:27:35Z,2013-08-24T16:35:52Z,lorenzo,MEMBER,lib/Cake/ORM/ResultCollectionTrait.php,,27,,,27,"@@ -0,0 +1,72 @@ ++_eventManager)) { + $this->_eventManager = new EventManager();","yes, I wanted to listen to a view render in a crud listener, but couldn't access the view to attach an event, since the view isn't created until render() is called - had to hack around it to make it work :) +I expected a View.beforeRender event in any class attaching to the controller event manager would have worked, but alas it did not :) +",0,c8f6c84285080bfc9020401522b01bb7d50777ab +4464918,0,"This permits SQL injection. User data should never be interpolated into the keys of a find condition.""",5/30/13 7:37,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1319#discussion_r4464918,2013-05-30T19:37:21Z,2013-05-30T19:37:21Z,markstory,MEMBER,lib/Cake/Console/Templates/default/actions/controller_actions.ctp,,182,,,26,"@@ -157,3 +157,62 @@ + + $this->redirect(array('action' => 'index')); + } ++ ++/** ++ * search method ++ * ++ * @return void ++ */ ++ public function search() { ++ if ($this->request->is('post') || $this->request->is('put')) { ++ $conditions = array(); ++ foreach ($this->data[''] as $key => $value) { ++ $empty = true; ++ if ((substr($key, -3) == ""_id"")) { // associated input have _id suffix ++ if ($value != 0) ++ $empty = false; ++ } else { ++ if ($value != """") ++ $empty = false; ++ } ++ ++ if (!$empty) { ++ if (strstr($value, ""*"")) { ++ $conditions[] = array( ++ '.'.$key."" LIKE"" => str_replace('*', '%', $value)","This permits SQL injection. User data should never be interpolated into the keys of a find condition. +",0,221f95f0af250cf48c90c350282af33478e5c15f +4394900,2,"Odd, it might be the test being wrong... I remember spending some time fixing the multi insert in sqlite so I was quite surprised it did not work.""",5/26/13 6:58,lorenzo,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1303#discussion_r4394900,2013-05-26T18:58:24Z,2013-05-29T02:13:15Z,lorenzo,MEMBER,lib/Cake/Database/Dialect/SqliteDialectTrait.php,,,,,1,"@@ -102,28 +102,33 @@ protected function _insertQueryTranslator($query) { + return $query; + } + +- $cols = $v->columns(); + $newQuery = $query->connection()->newQuery(); ++ $cols = $v->columns(); + $values = []; + foreach ($v->values() as $k => $val) { + $values[] = $val; +- $val = array_merge($val, array_fill(0, count($cols) - count($val), null)); ++ $fillLength = count($cols) - count($val); ++ if ($fillLength > 0) { ++ $val = array_merge($val, array_fill(0, $fillLength, null)); ++ } ++ // TODO this doesn't work all columns are inserted as null.","Odd, it might be the test being wrong... I remember spending some time fixing the multi insert in sqlite so I was quite surprised it did not work. +",0,2b90e7dbc75cccae5f7b1fc76eba57bf6fcbe049 +3613646,0,"10, integers in postgres are signed so one of the bits is used for the sign. It is actually the same in Mysql, unless it is declared as unsigned""",4/1/13 19:44,lorenzo,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1212#discussion_r3613646,2013-04-02T07:44:51Z,2013-04-03T21:35:55Z,lorenzo,MEMBER,lib/Cake/Model/Datasource/Database/Dialect/PostgresDialectTrait.php,,205,,,58,"@@ -148,4 +148,128 @@ protected function _transformFunctionExpression(FunctionExpression $expression) + } + } + ++/** ++ * Get the SQL to list the tables ++ * ++ * @param array $config The connection configuration to use for ++ * getting tables from. ++ * @return array An array of (sql, params) to execute. ++ */ ++ public function listTablesSql($config) { ++ $sql = ""SELECT table_name as name FROM INFORMATION_SCHEMA.tables WHERE table_schema = ? ORDER BY name""; ++ $schema = empty($config['schema']) ? 'public' : $config['schema']; ++ return [$sql, [$schema]]; ++ } ++ ++/** ++ * Get the SQL to describe a table in Postgres. ++ * ++ * @param string $table The table name to describe ++ * @param array $config The connection configuration to use ++ * @return array An array of (sql, params) to execute. ++ */ ++ public function describeTableSql($table, $config) { ++ $sql = ++ ""SELECT DISTINCT table_schema AS schema, column_name AS name, data_type AS type, ++ is_nullable AS null, column_default AS default, ordinal_position AS position, ++ character_maximum_length AS char_length, character_octet_length AS oct_length, ++ d.description as comment, i.indisprimary = 't' as pk ++ FROM information_schema.columns c ++ INNER JOIN pg_catalog.pg_namespace ns ON (ns.nspname = table_schema) ++ INNER JOIN pg_catalog.pg_class cl ON (cl.relnamespace = ns.oid AND cl.relname = table_name) ++ LEFT JOIN pg_catalog.pg_index i ON (i.indrelid = cl.oid AND i.indkey[0] = c.ordinal_position) ++ LEFT JOIN pg_catalog.pg_description d on (cl.oid = d.objoid AND d.objsubid = c.ordinal_position) ++ WHERE table_name = ? AND table_schema = ? ORDER BY position""; ++ $schema = empty($config['schema']) ? 'public' : $config['schema']; ++ return [$sql, [$table, $schema]]; ++ } ++ ++/** ++ * Convert a column definition to the abstract types. ++ * ++ * The returned type will be a type that ++ * Cake\Model\Datasource\Database\Type can handle. ++ * ++ * @param string $column The column type + length ++ * @return array List of (type, length) ++ */ ++ public function convertColumn($column) { ++ $col = strtolower($column); ++ if (in_array($col, array('date', 'time', 'boolean'))) { ++ return [$col, null]; ++ } ++ if (strpos($col, 'timestamp') !== false) { ++ return ['datetime', null]; ++ } ++ if ($col === 'serial' || $col === 'integer') { ++ return ['integer', 10];","10, integers in postgres are signed so one of the bits is used for the sign. It is actually the same in Mysql, unless it is declared as unsigned +",0,caec717bce20e06429dd54bafe39b4b0ee6682bb +3622375,2,"Derp, I missed that sorry.""",4/2/13 5:23,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1212#discussion_r3622375,2013-04-02T17:23:11Z,2013-04-03T21:35:55Z,markstory,MEMBER,lib/Cake/Test/TestCase/Model/Datasource/Database/Driver/PostgresTest.php,,343,,,225,"@@ -126,4 +129,218 @@ public function testConnectionConfigCustom() { + $driver->connect($config); + } + ++/** ++ * Helper method for skipping tests that need a real connection. ++ * ++ * @return void ++ */ ++ protected function _needsConnection() { ++ $config = Configure::read('Datasource.test'); ++ $this->skipIf(strpos($config['datasource'], 'Postgres') === false, 'Not using Postgres for test config'); ++ } ++ ++/** ++ * Helper method for testing methods. ++ * ++ * @return void ++ */ ++ protected function _createTables($connection) { ++ $this->_needsConnection(); ++ $connection->execute('DROP TABLE IF EXISTS articles'); ++ $connection->execute('DROP TABLE IF EXISTS authors'); ++ ++ $table = <<execute($table); ++ ++ $table = <<execute($table); ++ $connection->execute('COMMENT ON COLUMN ""articles"".""title"" IS \'a title\''); ++ } ++ ++/** ++ * Dataprovider for column testing ++ * ++ * @return array ++ */ ++ public static function columnProvider() { ++ return [ ++ [ ++ 'TIMESTAMP', ++ ['datetime', null] ++ ], ++ [ ++ 'TIMESTAMP WITHOUT TIME ZONE', ++ ['datetime', null] ++ ], ++ [ ++ 'DATE', ++ ['date', null] ++ ], ++ [ ++ 'TIME', ++ ['time', null] ++ ], ++ [ ++ 'SMALLINT', ++ ['integer', 5] ++ ], ++ [ ++ 'INTEGER', ++ ['integer', 10] ++ ], ++ [ ++ 'SERIAL', ++ ['integer', 10] ++ ], ++ [ ++ 'BIGINT', ++ ['biginteger', 20] ++ ], ++ [ ++ 'NUMERIC', ++ ['decimal', null] ++ ], ++ [ ++ 'VARCHAR', ++ ['string', null] ++ ], ++ [ ++ 'CHARACTER VARYING', ++ ['string', null] ++ ], ++ [ ++ 'CHAR', ++ ['string', null] ++ ], ++ [ ++ 'CHARACTER', ++ ['string', null] ++ ], ++ [ ++ 'TEXT', ++ ['text', null] ++ ], ++ [ ++ 'BYTEA', ++ ['binary', null] ++ ], ++ [ ++ 'REAL', ++ ['float', null] ++ ], ++ [ ++ 'DOUBLE PRECISION', ++ ['float', null] ++ ], ++ [ ++ 'BIGSERIAL', ++ ['biginteger', 20] ++ ], ++ ]; ++ } ++ ++/** ++ * Test parsing Postgres column types. ++ * ++ * @dataProvider columnProvider ++ * @return void ++ */ ++ public function testConvertColumnType($input, $expected) { ++ $driver = new Postgres(); ++ $this->assertEquals($expected, $driver->convertColumn($input)); ++ } ++ ++ ++/** ++ * Test listing tables with Postgres ++ * ++ * @return void ++ */ ++ public function testListTables() { ++ $connection = new Connection(Configure::read('Datasource.test')); ++ $this->_createTables($connection); ++ ++ $result = $connection->listTables(); ++ $this->assertInternalType('array', $result); ++ $this->assertCount(2, $result); ++ $this->assertEquals('articles', $result[0]); ++ $this->assertEquals('authors', $result[1]); ++ } ++ ++/** ++ * Test describing a table with Postgres ++ * ++ * @return void ++ */ ++ public function testDescribeTable() { ++ $connection = new Connection(Configure::read('Datasource.test')); ++ $this->_createTables($connection); ++ ++ $result = $connection->describe('articles'); ++ $expected = [ ++ 'id' => [ ++ 'type' => 'biginteger', ++ 'null' => false, ++ 'default' => null, ++ 'length' => 20, ++ 'key' => 'primary', ++ ], ++ 'title' => [ ++ 'type' => 'string', ++ 'null' => true, ++ 'default' => null, ++ 'length' => 20, ++ 'comment' => 'a title', ++ ], ++ 'body' => [ ++ 'type' => 'text', ++ 'null' => true, ++ 'default' => null, ++ 'length' => null, ++ ], ++ 'author_id' => [ ++ 'type' => 'integer', ++ 'null' => false, ++ 'default' => null, ++ 'length' => 10, ++ ], ++ 'published' => [ ++ 'type' => 'boolean', ++ 'null' => true, ++ 'default' => 0, ++ 'length' => null, ++ ], ++ 'views' => [ ++ 'type' => 'integer', ++ 'null' => true, ++ 'default' => 0, ++ 'length' => 5, ++ ], ++ 'created' => [ ++ 'type' => 'datetime', ++ 'null' => true, ++ 'default' => null, ++ 'length' => null, ++ ], ++ ]; ++ $this->assertEquals($expected, $result);","Derp, I missed that sorry. +",0,caec717bce20e06429dd54bafe39b4b0ee6682bb +1941298,0,"Extra space after `(` and before `)`. If block should always have braces `{}` even for single lines.""",10/25/12 2:34,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/913#discussion_r1941298,2012-10-25T14:34:46Z,2013-01-20T08:13:45Z,ADmad,MEMBER,lib/Cake/Model/Validator/CakeValidationRule.php,,,,,1,"@@ -271,6 +274,13 @@ public function process($field, &$data, &$methods) { + $this->_valid = call_user_func_array($methods[$rule], $this->_ruleParams); + } elseif (class_exists('Validation') && method_exists('Validation', $this->_rule)) { + $this->_valid = call_user_func_array(array('Validation', $this->_rule), $this->_ruleParams); ++ } elseif (strpos($this->_rule ,'::')) { ++ list($plugin, $class) = pluginSplit($this->_rule); ++ list($className,$method) = explode('::',$class); ++ $location = 'Model/Validation'; ++ if ( $plugin ) $location = $plugin . '.' . $location;","Extra space after `(` and before `)`. If block should always have braces `{}` even for single lines. +",0,b2cbeeeb501285431bdc7fb2a5b37f260b792261 +1714815,0,"Indentation is still incorrect, better use the code sniffer.""",9/27/12 17:55,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/872#discussion_r1714815,2012-09-28T05:55:21Z,2012-09-28T06:07:43Z,ADmad,MEMBER,lib/Cake/Cache/Engine/WincacheEngine.php,,,,,1,"@@ -183,6 +183,7 @@ public function groups() { + * @return boolean success + **/ + public function clearGroup($group) { ++ $success = null;","Indentation is still incorrect, better use the code sniffer. +",0,f4565d51fad4ba81906f085cd5abf043d4852365 +1460045,2,"Having a destructive get() seems like a bad idea. Why not just call set() afterwards to clear the block. I'd like to avoid duplicated functionality.""",8/25/12 9:11,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/795#discussion_r1460045,2012-08-25T21:11:14Z,2012-08-25T21:19:27Z,markstory,MEMBER,lib/Cake/View/ViewBlock.php,,125,,,8,"@@ -119,13 +119,18 @@ public function set($name, $value) { + * Get the content for a block. + * + * @param string $name Name of the block ++ * @param boolean $clear Whether or not to clear the block after retrieval (default false) + * @return The block content or '' if the block does not exist. + */ +- public function get($name) { ++ public function get($name, $clear = false) {","Having a destructive get() seems like a bad idea. Why not just call set() afterwards to clear the block. I'd like to avoid duplicated functionality. +",0,123a59baa20c336a089956e00a4f88b6f8d95860 +408211,1,"Yeah, true, But I dunno if it would break userland code if init() would not register the Behavior in the Collection, but instead do nothing. But I trust your judgement in these things :-)""",2/1/12 11:02,tPl0ch,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/455#discussion_r408211,2012-02-01T22:02:29Z,2012-02-03T18:33:39Z,tPl0ch,NONE,lib/Cake/Model/BehaviorCollection.php,,82,,,1,"@@ -70,6 +69,18 @@ public function init($modelName, $behaviors = array()) { + } + + /** ++ * Backwards compatible alias for __construct() ++ * ++ * @param string $modelName ++ * @param array $behaviors ++ * @return void ++ * @deprecated Initialize with constructor instead ++ */ ++ public function init($modelName, $behaviors = array()) { ++ $this->__construct($modelName, $behaviors); ++ } ++ ++/**","Yeah, true, But I dunno if it would break userland code if init() would not register the Behavior in the Collection, but instead do nothing. But I trust your judgement in these things :-) +",0,ea4f39c13bb80524ad470196be75d5a6a6964048 +54071,2,"Yeah, that's right. My bad. Commit 788a7e4 corrects this issue.""",6/28/11 11:01,luisarmando,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/136#discussion_r54071,2011-06-28T23:01:01Z,2011-07-01T10:19:38Z,labianchin,CONTRIBUTOR,lib/Cake/Console/Command/UpgradeShell.php,,,,,1,"@@ -74,16 +74,22 @@ class UpgradeShell extends Shell { + public function locations() { + $cwd = getcwd(); + +- if (is_dir('plugins')) { +- +- $Folder = new Folder('plugins'); +- list($plugins) = $Folder->read(); +- foreach($plugins as $plugin) { +- chdir($cwd . DS . 'plugins' . DS . $plugin); +- $this->locations(); ++ $plugins = App::path('plugins'); ++ if (!$pluginsFolders) ++ $pluginsFolders = array('plugins'); ++ ++ foreach ($pluginsFolders as $pluginsFolder){ ++ if (is_dir($pluginsFolder)) { ++ ++ $Folder = new Folder($pluginsFolder); ++ list($plugins) = $Folder->read(); ++ foreach($plugins as $plugin) { ++ chdir($cwd . DS . 'plugins' . DS . $plugin);","Yeah, that's right. My bad. +Commit 788a7e4 corrects this issue. +",0,b22e30c5a31fb8a7ff95f6670193bc7697de0e9a +6630638,0,"You can also use the official [code sniffer](https://github.com/cakephp/cakephp-codesniffer).""",9/27/13 3:27,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1688#discussion_r6630638,2013-09-27T15:27:07Z,2013-09-27T15:27:07Z,ADmad,MEMBER,lib/Cake/TestSuite/ControllerTestCase.php,,,,,1,"@@ -219,7 +219,8 @@ protected function _testAction($url = '', $options = array()) { + $options = array_merge(array( + 'data' => array(), + 'method' => 'POST', +- 'return' => 'result' ++ 'return' => 'result', ++ 'named' => array()","You can also use the official [code sniffer](https://github.com/cakephp/cakephp-codesniffer). +",0,9faf3ca5d46ad908974d590249083b5dd75971b9 +2671628,0,"Just as curiosity, I was looking the [`DateTime` documentation](http://us2.php.net/manual/en/class.datetime.php) today and they have the constant for the RFC formats. Form the [cookie RFC](http://tools.ietf.org/html/rfc2616#section-3.3.1), it could be """,1/16/13 9:19,jrbasso,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1057#discussion_r2671628,2013-01-16T20:19:39Z,2013-01-24T02:45:59Z,jrbasso,MEMBER,lib/Cake/Network/Http/Cookies.php,,,,,1,"@@ -0,0 +1,117 @@ ++cookies(); ++ foreach ($cookies as $name => $cookie) { ++ if (empty($cookie['domain'])) { ++ $cookie['domain'] = $host; ++ } ++ if (empty($cookie['path'])) { ++ $cookie['path'] = $path; ++ } ++ $key = implode(';', [$cookie['name'], $cookie['domain'], $cookie['path']]); ++ ++ $expires = isset($cookie['expires']) ? $cookie['expires'] : false; ++ if ($expires) { ++ $expires = \DateTime::createFromFormat('D, j-M-Y H:i:s e', $expires);","Just as curiosity, I was looking the [`DateTime` documentation](http://us2.php.net/manual/en/class.datetime.php) today and they have the constant for the RFC formats. + +Form the [cookie RFC](http://tools.ietf.org/html/rfc2616#section-3.3.1), it could be ISO 1123 (most used and the same you used), RFC 1036 or asctime(). +",0,c0865001dc9b44d763aba9eaa00720fa4e485ddc +2676081,0,"I ended up using `strtotime()` as the various formats that I saw in the wild and in the specs resulted in icky code. However, strtotime() seems to be able to sort everything out.""",1/16/13 15:06,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1057#discussion_r2676081,2013-01-17T02:06:50Z,2013-01-24T02:45:59Z,markstory,MEMBER,lib/Cake/Network/Http/Cookies.php,,,,,1,"@@ -0,0 +1,117 @@ ++cookies(); ++ foreach ($cookies as $name => $cookie) { ++ if (empty($cookie['domain'])) { ++ $cookie['domain'] = $host; ++ } ++ if (empty($cookie['path'])) { ++ $cookie['path'] = $path; ++ } ++ $key = implode(';', [$cookie['name'], $cookie['domain'], $cookie['path']]); ++ ++ $expires = isset($cookie['expires']) ? $cookie['expires'] : false; ++ if ($expires) { ++ $expires = \DateTime::createFromFormat('D, j-M-Y H:i:s e', $expires);","I ended up using `strtotime()` as the various formats that I saw in the wild and in the specs resulted in icky code. However, strtotime() seems to be able to sort everything out. +",0,c0865001dc9b44d763aba9eaa00720fa4e485ddc +4778220,1,"Yes you right""",6/19/13 5:36,bhiv,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1364#discussion_r4778220,2013-06-19T17:36:15Z,2013-06-19T17:36:15Z,np42,NONE,lib/Cake/Model/Behavior/ContainableBehavior.php,,163,,,19,"@@ -152,6 +157,12 @@ public function beforeFind(Model $Model, $query) { + if (!$reset && empty($instance->__backOriginalAssociation)) { + $instance->__backOriginalAssociation = $backupBindings; + } ++ foreach ($unbind as $className) { ++ $this->rebinds[] = array ++ ( 'model' => $instance, 'type' => $type ++ , 'className' => $className, 'link' => &$instance->{$type}[$className]","Yes you right +",0,8e500c33349a5dbd05d1846c17538102669a5c51 +6103651,0,"One could default this to false and only enable it dynamically inside the code.""",9/1/13 10:55,dereuromark,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1594#discussion_r6103651,2013-09-01T22:55:17Z,2013-09-01T22:55:17Z,dereuromark,MEMBER,lib/Cake/Console/ConsoleInput.php,,44,,,12,"@@ -33,11 +33,23 @@ class ConsoleInput { + protected $_input; + + /** ++ * Can this instance use readline? ++ * Two conditions must be met: ++ * 1. Readline support must be enabled. ++ * 2. Handle we are attached to must be stdin. ++ * Allows rich editing with arrow keys and history when inputting a string. ++ * ++ * @var bool ++ */ ++ protected $_canReadline;","One could default this to false and only enable it dynamically inside the code. +",0,bb98ac761fad08204cb7ad9fac9e6b22e283f5e0 +6060336,0,"One problem with pbkdf is the general lack of support. Prior to 5.5 I'm not aware of any commonly installed extension that provides pbkdf2. An alternative to length checks and pbkdf2 is to use sha256. That would mask the original key and ensure the correc""",8/29/13 1:40,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1568#discussion_r6060336,2013-08-29T13:40:49Z,2013-09-02T01:44:56Z,markstory,MEMBER,lib/Cake/Utility/Security.php,,,,,1,"@@ -289,4 +289,69 @@ protected static function _crypt($password, $salt = false) { + return crypt($password, $salt); + } + ++/** ++ * Encrypt a value using AES-256. ++ * ++ * *Caveat* You cannot properly encrypt/decrypt data with trailing null bytes. ++ * Any trailing null bytes will be removed on decryption due to how PHP pads messages ++ * with nulls prior to encryption. ++ * ++ * @param string $plain The value to encrypt. ++ * @param string $key The 256 bit/32 byte key to use as a cipher key. ++ * @return string Encrypted data. ++ * @throws CakeException On invalid data or key. ++ */ ++ public static function encrypt($plain, $key) { ++ self::_checkKey($key, 'encrypt()'); ++ if (empty($plain)) { ++ throw new CakeException(__d('cake_dev', 'The data to encrypt cannot be empty.')); ++ } ++ $key = substr($key, 0, 32);","One problem with pbkdf is the general lack of support. Prior to 5.5 I'm not aware of any commonly installed extension that provides pbkdf2. An alternative to length checks and pbkdf2 is to use sha256. That would mask the original key and ensure the correct key length. +",0,13b870d7e183375822eea4ffd66aaacaeec760ff +5034403,2,"Sounds like hack, but with that difference I wonder if the `call_user_func_array` could be replaced until certain level by the same strategy used in [`Configure::write()` of 1.x version](https://github.com/cakephp/cakephp/blob/1.3/cake/libs/configure.php#""",7/4/13 5:25,jrbasso,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1397#discussion_r5034403,2013-07-04T17:25:21Z,2013-07-05T03:45:44Z,jrbasso,MEMBER,lib/Cake/Event/EventManager.php,,,,,1,"@@ -243,8 +235,10 @@ public function dispatch($event) { + if ($event->isStopped()) { + break; + } +- if ($listener['passParams'] === true) { +- $result = call_user_func_array($listener['callable'], $event->data); ++ $data = $event->data(); ++ if ($data !== null) { ++ array_unshift($data, $event); ++ $result = call_user_func_array($listener['callable'], $data); + } else { + $result = call_user_func($listener['callable'], $event);","Sounds like hack, but with that difference I wonder if the `call_user_func_array` could be replaced until certain level by the same strategy used in [`Configure::write()` of 1.x version](https://github.com/cakephp/cakephp/blob/1.3/cake/libs/configure.php#L93-L107) +",0,3040dbe0c36960df4b3d20fd0cad8a570a98cdff +4288375,0,"It is needed and is set in [constructor](https://github.com/ADmad/cakephp/blob/8ae3934378e75b2bdc7ac850f7593467fa7e7fc3/lib/Cake/Controller/Component/Auth/BasicAuthenticate.php#L55). I removed the overriding of `$settings` property so that if its keys are""",5/18/13 4:35,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1275#discussion_r4288375,2013-05-18T16:35:27Z,2013-05-26T05:59:44Z,ADmad,MEMBER,lib/Cake/Controller/Component/Auth/BasicAuthenticate.php,,68,,,25,"@@ -44,31 +44,6 @@ + class BasicAuthenticate extends BaseAuthenticate { + + /** +- * Settings for this object. +- * +- * - `fields` The fields to use to identify a user by. +- * - `userModel` The model name of the User, defaults to User. +- * - `scope` Additional conditions to use when looking up and authenticating users, +- * i.e. `array('User.is_active' => 1).` +- * - `recursive` The value of the recursive key passed to find(). Defaults to 0. +- * - `contain` Extra models to contain and store in session. +- * - `realm` The realm authentication is for. Defaults the server name. +- * +- * @var array +- */ +- public $settings = array( +- 'fields' => array( +- 'username' => 'username', +- 'password' => 'password' +- ), +- 'userModel' => 'User', +- 'scope' => array(), +- 'recursive' => 0, +- 'contain' => null, +- 'realm' => '',","It is needed and is set in [constructor](https://github.com/ADmad/cakephp/blob/8ae3934378e75b2bdc7ac850f7593467fa7e7fc3/lib/Cake/Controller/Component/Auth/BasicAuthenticate.php#L55). I removed the overriding of `$settings` property so that if its keys are updated in `BaseAuthenticate` they are easily inherited and you don't have to update this class too. +",0,dd2892ad8d0e3a0b09990b0a9ef26c320f1901fa +2930599,0,"should the regex then consider the following? ```html
,
,
,
``` Mark, I'm not sure if I follow the tag formatting that you've created and how it would account for the 4 versions of 'br' above?""",2/7/13 7:07,TeckniX,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1107#discussion_r2930599,2013-02-07T18:07:30Z,2013-03-25T15:01:22Z,TeckniX,CONTRIBUTOR,lib/Cake/View/Helper/TextHelper.php,,,,,1,"@@ -228,6 +228,29 @@ public function highlight($text, $phrase, $options = array()) { + } + + /** ++ * Formats paragraphs around given text for all line breaks ++ *
added for single line return ++ *

added for double line return ++ * ++ * @param string $text Text ++ * @return string The text with proper

tags ++ * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/text.html#TextHelper::autoParagraph ++ */ ++ public static function autoParagraph($text) { ++ if (trim($text) !== '') { ++ $text = preg_replace('|
\s*
|', ""\n\n"", $text . ""\n"");","should the regex then consider the following? + +``` html +
,
,
,
+``` + +Mark, I'm not sure if I follow the tag formatting that you've created and how it would account for the 4 versions of 'br' above? +",0,d260f4a5b3c4e057355397da65ab7f8a3088d5a7 +1616412,0,"Can you please rename it to addToWhitelist ? First time I read this I thought it was ment to add fields to a query""",9/16/12 19:33,lorenzo,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/851#discussion_r1616412,2012-09-17T07:33:50Z,2012-11-02T09:54:29Z,lorenzo,MEMBER,lib/Cake/Model/Model.php,,,,,1,"@@ -2299,6 +2302,29 @@ public function saveAssociated($data = null, $options = array()) { + } + + /** ++ * Helper method for saveAll() and friends, to add foreign key to fieldlist ++ * ++ * @param string $key fieldname to be added to list ++ * @param array $options ++ * @return array $options ++ */ ++ public function addToFieldList($key, $options) {","Can you please rename it to addToWhitelist ? First time I read this I thought it was ment to add fields to a query +",0,7007dba0eb836f852aaca95fada103bc4ba993a9 +1620325,0,"fieldList == whiteList though.""",9/17/12 4:39,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/851#discussion_r1620325,2012-09-17T16:39:36Z,2012-11-02T09:54:30Z,markstory,MEMBER,lib/Cake/Model/Model.php,,,,,1,"@@ -2299,6 +2302,29 @@ public function saveAssociated($data = null, $options = array()) { + } + + /** ++ * Helper method for saveAll() and friends, to add foreign key to fieldlist ++ * ++ * @param string $key fieldname to be added to list ++ * @param array $options ++ * @return array $options ++ */ ++ public function addToFieldList($key, $options) {","fieldList == whiteList though. +",0,7007dba0eb836f852aaca95fada103bc4ba993a9 +1616459,2,"Can we add a default return? throwing an exception sounds a bit too much for view related code""",9/16/12 19:47,lorenzo,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/850#discussion_r1616459,2012-09-17T07:47:21Z,2012-09-17T11:22:15Z,lorenzo,MEMBER,lib/Cake/Utility/CakeNumber.php,,127,,,1,"@@ -102,6 +102,28 @@ public static function toReadableSize($size) { + } + + /** ++ * Converts filesize from human readable string to bytes ++ * ++ * @param string $size Size in human readable string like '5MB' ++ * @return integer Bytes ++ */ ++ public static function fromReadableSize($size) { ++ if (ctype_digit($size)) { ++ return $size * 1; ++ } ++ $units = array('KB', 'MB', 'GB', 'TB', 'PB'); ++ foreach ($units as $i => $unit) { ++ if ($unit == substr($size, -2)) { ++ return $size * pow(1024, $i + 1); ++ } ++ } ++ if (substr($size, -1) == 'B' && ctype_digit(substr($size, 0, strlen($size) - 1))) { ++ return $size * 1; ++ } ++ throw new CakeException(__d('cake_dev', 'No unit type.'));","Can we add a default return? throwing an exception sounds a bit too much for view related code +",0,9530e68ae62dc9cb49b00e61814165c46009f56e +1560837,0,"Why not have the _setupFilesystem() method return a list of variables that you can unpack with list(). That solves the duplication and variable scoping issues.""",9/8/12 5:35,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/626#discussion_r1560837,2012-09-08T17:35:24Z,2012-09-08T17:35:24Z,markstory,MEMBER,lib/Cake/Test/Case/Utility/FolderTest.php,,1023,,,62,"@@ -848,14 +973,76 @@ public function testCopy() { + file_put_contents($folderThree . DS . 'folder2' . DS . 'file2.php', 'untouched'); + + $Folder = new Folder($folderOne); +- $result = $Folder->copy($folderThree); ++ $result = $Folder->copy(array('to'=>$folderThree, 'scheme'=>Folder::SKIP)); + $this->assertTrue($result); + $this->assertTrue(file_exists($folderThree . DS . 'file1.php')); + $this->assertEquals('untouched', file_get_contents($folderThree . DS . 'folder2' . DS . 'file2.php')); + + $Folder = new Folder($path); + $Folder->delete(); ++ } ++ ++ /** ++ * testCopyWithOverwrite ++ * ++ * Verify that subdirectories existing in both destination and source directory ++ * are overwritten/replaced recursivly. ++ * ++ * $path: folder_test/ ++ * $folderOne: folder_test/folder1/ ++ * - file1.php ++ * $folderTwo: folder_test/folder2/ ++ * - file2.php ++ * $folderThree: folder_test/folder1/folder3/ ++ * - file3.php ++ * $folderFour: folder_test/folder2/folder4/ ++ * - file4.php ++ * $folderFive: folder_test/folder4/ ++ */ ++ function testCopyWithOverwrite() { ++ $path = TMP . 'folder_test'; ++ $folderOne = $path . DS . 'folder1'; ++ $folderTwo = $path . DS . 'folder2'; ++ $folderThree = $folderOne . DS . 'folder'; ++ $folderFour = $folderTwo . DS . 'folder'; ++ $folderFive = $path . DS . 'folder5'; ++ $fileOne = $folderOne . DS . 'file1.php'; ++ $fileTwo = $folderTwo . DS . 'file2.php'; ++ $file3 = $folderThree . DS . 'file3.php'; ++ $file4 = $folderFour . DS . 'file4.php'; ++ ++ new Folder($path, true); ++ new Folder($folderOne, true); ++ new Folder($folderTwo, true); ++ new Folder($folderThree, true); ++ new Folder($folderFour, true); ++ new Folder($folderFive, true); ++ touch($fileOne); ++ touch($fileTwo); ++ touch($file3); ++ touch($file4);","Why not have the _setupFilesystem() method return a list of variables that you can unpack with list(). That solves the duplication and variable scoping issues. +",0,0a35f514cb07b016ac7bd1b904a273b6a0026d05 +165826,1,"I think the mask config option is useful. I just think that chmod() has no chance of side effects in a multi-threaded webserver unlike umask()""",10/11/11 13:29,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/240#discussion_r165826,2011-10-12T01:29:24Z,2011-10-12T08:20:12Z,markstory,MEMBER,lib/Cake/Cache/Engine/FileEngine.php,,,,,1,"@@ -288,9 +283,10 @@ class FileEngine extends CacheEngine { + if (!$createKey && !$path->isFile()) { + return false; + } +- $old = umask(0); ++ ++ $old = umask(0666 & ~$this->settings['mask']);","I think the mask config option is useful. I just think that chmod() has no chance of side effects in a multi-threaded webserver unlike umask() +",0,40aeabe03afb523261c36d3da690d1527207412b +6632562,1,"Returning early for `if (Configure::read('Cache.check') === true) {` would be great too!""",9/27/13 4:41,renan,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1687#discussion_r6632562,2013-09-27T16:41:53Z,2013-09-28T08:19:33Z,renan,CONTRIBUTOR,lib/Cake/Model/Model.php,,,,,1,"@@ -3501,17 +3501,20 @@ public function onError() { + protected function _clearCache($type = null) { + if ($type === null) {","Returning early for `if (Configure::read('Cache.check') === true) {` would be great too! +",0,be61a5023f6052b7765bddfb3b29e52407d0df85 +4779589,0,"beeing => being and singup => signup ?""",6/19/13 6:22,dereuromark,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1352#discussion_r4779589,2013-06-19T18:22:19Z,2013-06-19T18:22:19Z,dereuromark,MEMBER,lib/Cake/Test/Case/View/Helper/FormHelperTest.php,,6636,,,8,"@@ -6629,6 +6629,31 @@ public function testYearAutoExpandRange() { + } + + /** ++ * testInputDateMaxYear method ++ * ++ * Let's say we want to only allow users born from ++ * 2006 to 2008 to register ++ * This beeing the first singup page, we still don't have any data","beeing => being and singup => signup ? +",0,2c2f357f30afb956187d89f84313ea268ff22ea9 +6374521,0,"If you want you can, if not I can go through and fix the old code. There isn't a phpcs test for this which is why it is inconsistent.""",9/15/13 23:55,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1638#discussion_r6374521,2013-09-16T11:55:27Z,2013-09-16T12:06:12Z,markstory,MEMBER,lib/Cake/Test/Case/Event/CakeEventManagerTest.php,,,,,1,"@@ -414,4 +422,63 @@ public function testStopPropagation() { + $expected = array('secondListenerFunction'); + $this->assertEquals($expected, $listener->callStack); + } ++ ++/** ++ * Tests event dispatching using priorities ++ * ++ * @return void ++ */ ++ public function testDispatchPrioritizedWithGlobal() { ++ $generalManager = $this->getMock('CakeEventManager'); ++ $manager = new CakeEventManager; ++ $listener = new CustomTestEventListerner;","If you want you can, if not I can go through and fix the old code. There isn't a phpcs test for this which is why it is inconsistent. +",0,8a87f7e1b56af69b3ac9b2df52ace9caad45e9f5 +6101204,2,":(""",8/31/13 11:25,jrbasso,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1584#discussion_r6101204,2013-08-31T23:25:29Z,2013-09-01T02:33:40Z,jrbasso,MEMBER,lib/Cake/ORM/Query.php,,,,,1,"@@ -558,6 +558,29 @@ public function mapReduce(callable $mapper = null, callable $reducer = null, $ov + } + + /** ++ * Returns the first result out of executed this query, if the query has not been ++ * executed before, it will set the limit clause to 1 for performance reasons. ++ * ++ * ###Example: ++ * ++ * ``$singleUser = $query->select(['id', 'username'])->first()`` ++ * ++ * @return mixed the first result from the ResultSet ++ */ ++ public function first() { ++ if ($this->_dirty) { ++ $this->limit(1); ++ } ++ $this->bufferResults(); ++ $this->_results = $this->execute(); ++ // Calls foreach so we cursor is rewinded automatically ++ foreach ($this->_results as $row) {",":( +",0,88c0ab3a2f5be7840d559e8873b0b6562e915416 +5829535,2,"I'm glad I'm not the only person who hates Cache::set(). That method is all sorts of silly. I'm on board for removing it if others are. It adds a pile of complexity to Cache for almost no benefit other than making the calling code more complicated as well""",8/17/13 6:44,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1534#discussion_r5829535,2013-08-17T18:44:30Z,2013-08-17T21:09:51Z,markstory,MEMBER,lib/Cake/Cache/Cache.php,,181,,,71,"@@ -125,25 +132,62 @@ class Cache { + + /** + * This method can be used to define cache adapters for an application +- * during the bootstrapping process. You can use this method to add new cache adapters +- * at runtime as well. New cache configurations will be constructed upon the next write. ++ * or read existing configuration. + * + * To change an adapter's configuration at runtime, first drop the adapter and then + * reconfigure it. + * + * Adapters will not be constructed until the first operation is done. + * ++ * ### Usage ++ * ++ * Reading config data back: ++ * ++ * `Cache::config('default');` ++ * ++ * Setting a cache engine up. ++ * ++ * `Cache::config('default', $settings);` ++ * ++ * Injecting a constructed adapter in: ++ * ++ * `Cache::config('default', $instance);` ++ * ++ * Using a factory function to get an adapter: ++ * ++ * `Cache::config('default', function () { return new FileEngine(); });` ++ * ++ * Configure multiple adapters at once: ++ * ++ * `Cache::config($arrayOfConfig);` ++ * + * @param string|array $key The name of the cache config, or an array of multiple configs. + * @param array $config An array of name => config data for adapter. +- * @return void ++ * @return mixed null when adding configuration and an array of configuration data when reading. ++ * @throws Cake\Error\Exception When trying to modify an existing config. + */ + public static function config($key, $config = null) { +- if ($config !== null && is_string($key)) { +- static::$_config[$key] = $config; ++ // Read config. ++ if ($config === null && is_string($key)) { ++ return isset(static::$_config[$key]) ? static::$_config[$key] : null; ++ } ++ if ($config === null && is_array($key)) { ++ foreach ($key as $name => $settings) { ++ static::config($name, $settings); ++ } + return; + } +- +- static::$_config = array_merge(static::$_config, $key); ++ if (isset(static::$_config[$key])) { ++ throw new Error\Exception(__d('cake_dev', 'Cannot reconfigure existing adapter ""%s""', $key));","I'm glad I'm not the only person who hates Cache::set(). That method is all sorts of silly. I'm on board for removing it if others are. It adds a pile of complexity to Cache for almost no benefit other than making the calling code more complicated as well. +",0,0ecdd6f5b831281d144abd821e93f9157897709d +5591330,0,"There are a number of classname checks throughout the new code. Would it make sense to have a simple class that implemented the ExpressionInterface that we could use to wrap other values with? That might help remove the various `instanceof` checks through""",8/5/13 9:50,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1479#discussion_r5591330,2013-08-05T21:50:16Z,2013-08-10T09:37:05Z,markstory,MEMBER,lib/Cake/Database/Query.php,,1209,,,196,"@@ -1157,8 +1182,27 @@ protected function _buildInsertPart($parts) { + * @param array $parts + * @return string SQL fragment. + */ +- protected function _buildValuesPart($parts) { +- return implode('', $parts); ++ protected function _buildValuesPart($parts, $generator) { ++ return implode('', $this->_stringifyExpressions($parts, $generator)); ++ } ++ ++/** ++ * Helper function used to covert ExpressionInterface objects inside an array ++ * into their string representation ++ * ++ * @param array $expression list of strings and ExpressionInterface objects ++ * @param ValueBinder $generator the placeholder generator to be used in expressions ++ * @return array ++ */ ++ protected function _stringifyExpressions(array $expressions, ValueBinder $generator) { ++ $result = []; ++ foreach ($expressions as $k => $expression) { ++ if ($expression instanceof ExpressionInterface) { ++ $expression = '(' . $expression->sql($generator) . ')'; ++ }","There are a number of classname checks throughout the new code. Would it make sense to have a simple class that implemented the ExpressionInterface that we could use to wrap other values with? That might help remove the various `instanceof` checks throughout the code as all values would implement the ExpressionInterface. +",0,8962e041fb4d9c46bb7cd809418d8f6f92cb2daf +5609729,2,"Blerg. Do we need/want to support that syntax?""",8/6/13 5:06,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1479#discussion_r5609729,2013-08-06T17:06:40Z,2013-08-10T09:37:05Z,markstory,MEMBER,lib/Cake/Database/Query.php,,,,,1,"@@ -1453,6 +1497,48 @@ public function defaultTypes(array $types = null) { + } + + /** ++ * Associates a query placeholder to a value and a type. ++ * ++ * If type is expressed as ""atype[]"" (note braces) then it will cause the ++ * placeholder to be re-written dynamically so if the value is an array, it ++ * will create as many placeholders as values are in it. For example ""string[]"" ++ * will create several placeholders of type string. ++ * ++ * @param string|integer $token placeholder to be replaced with quoted version ++ * of $value ++ * @param mixed $value the value to be bound ++ * @param string|integer $type the mapped type name, used for casting when sending ++ * to database ++ * @return Query ++ */ ++ public function bind($param, $value, $type) {","Blerg. Do we need/want to support that syntax? +",0,8962e041fb4d9c46bb7cd809418d8f6f92cb2daf +4604322,0,"Yes, please.""",6/9/13 3:19,Phally,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1340#discussion_r4604322,2013-06-09T15:19:14Z,2013-06-16T04:10:38Z,Phally,CONTRIBUTOR,lib/Cake/Database/Expression/QueryExpression.php,,,,,1,"@@ -551,9 +551,12 @@ protected function _parseCondition($field, $value, $types) { + $type = isset($types[$expression]) ? $types[$expression] : null; + $multi = false; + +- if (in_array(strtolower(trim($operator)), ['in', 'not in'])) { ++ $typeMultiple = strpos($type, '[]') !== false; ++ if (in_array(strtolower(trim($operator)), ['in', 'not in']) || $typeMultiple) { + $type = $type ?: 'string'; +- $type .= strpos($type, '[]') === false ? '[]' : null; ++ $type .= $typeMultiple ? null : '[]'; ++ $operator = $operator == '=' ? 'in' : $operator; ++ $operator = $operator == '!=' ? 'not in' : $operator;","Yes, please. +",0,adb78e6c3992279bb0dcede982f7ba86db765a25 +4412256,1,"I like. It's not obvious in the diff, but does this allow setting the value 'once' like so: ```php $this->Html->pathPrefix = '//cakephp.org/css'; $this->Html->css('foo'); // http://cakephp.org/css/foo.css $this->Html->css(array('bar', 'spam'); //""",5/28/13 1:15,rchavik,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1305#discussion_r4412256,2013-05-28T13:15:40Z,2013-08-07T02:45:05Z,rchavik,MEMBER,lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php,,421,,,21,"@@ -386,6 +386,15 @@ public function testImageTag() { + + $result = $this->Html->image('test.gif?one=two&three=four'); + $this->assertTags($result, array('img' => array('src' => 'img/test.gif?one=two&three=four', 'alt' => ''))); ++ ++ $result = $this->Html->image('test.gif', array('pathPrefix' => '/my/custom/path/')); ++ $this->assertTags($result, array('img' => array('src' => '/my/custom/path/test.gif', 'alt' => ''))); ++ ++ $result = $this->Html->image('test.gif', array('pathPrefix' => 'http://cakephp.org/assets/img/')); ++ $this->assertTags($result, array('img' => array('src' => 'http://cakephp.org/assets/img/test.gif', 'alt' => ''))); ++ ++ $result = $this->Html->image('test.gif', array('pathPrefix' => '//cakephp.org/assets/img/'));","I like. + +It's not obvious in the diff, but does this allow setting the value 'once' like so: + +``` php +$this->Html->pathPrefix = '//cakephp.org/css'; +$this->Html->css('foo'); // http://cakephp.org/css/foo.css +$this->Html->css(array('bar', 'spam'); // http://cakephp.org/css/bar.css http://cakephp.org/css/spam.css +``` +",0,cda1a1e6c996ac91d7f0794b4134889f7f711024 +4288362,0,"Could you not use array_merge() here? None of the built-in hashers have nested settings.""",5/18/13 4:27,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1275#discussion_r4288362,2013-05-18T16:27:10Z,2013-05-26T05:59:44Z,markstory,MEMBER,lib/Cake/Controller/Component/Auth/BasePasswordHasher.php,,,,,1,"@@ -0,0 +1,66 @@ ++settings = Hash::merge($this->settings, $settings);","Could you not use array_merge() here? None of the built-in hashers have nested settings. +",0,dd2892ad8d0e3a0b09990b0a9ef26c320f1901fa +2741043,0,"Better to use the `cake.power.gif` image from `Test/test_app/`. Also as per cake's coding standard there should be a space before and after each `.`. You can use https://github.com/cakephp/cakephp-codesniffer """,1/23/13 1:44,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1080#discussion_r2741043,2013-01-23T12:44:24Z,2013-01-23T12:53:25Z,ADmad,MEMBER,lib/Cake/Test/Case/BasicsTest.php,,,,,1,"@@ -242,6 +242,10 @@ public function testH() { + $obj = new CakeResponse(array('body' => 'Body content')); + $result = h($obj); + $this->assertEquals('Body content', $result); ++ ++ $invalidString = file_get_contents(CAKE.'..'.DS.'..'.DS.'app'.DS.'webroot'.DS.'favicon.ico');","Better to use the `cake.power.gif` image from `Test/test_app/`. Also as per cake's coding standard there should be a space before and after each `.`. You can use https://github.com/cakephp/cakephp-codesniffer +",0,29326d77308437c1557843c090ef7ab77ac94c88 +2521324,0,"That's quite the selection in behaviour. This is all to handle the case where the referring URL & loginRedirect are inaccessible to the user who is logged in?""",12/30/12 4:17,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1053#discussion_r2521324,2012-12-30T15:17:59Z,2013-01-12T05:57:49Z,markstory,MEMBER,lib/Cake/Controller/Component/AuthComponent.php,,222,,,1,"@@ -215,11 +215,13 @@ class AuthComponent extends Component { + public $authError = null; + + /** +- * Controls handling of unauthorized access. By default unauthorized user is +- * redirected to the referrer url or AuthComponent::$loginRedirect or '/'. +- * If set to false a ForbiddenException exception is thrown instead of redirecting. ++ * Controls handling of unauthorized access. ++ * - For default value `true` unauthorized user is redirected to the referrer url ++ * or AuthComponent::$loginRedirect or '/'. ++ * - If set to a string or array the value is used as an url to redirect to. ++ * - If set to false a ForbiddenException exception is thrown instead of redirecting.","That's quite the selection in behaviour. This is all to handle the case where the referring URL & loginRedirect are inaccessible to the user who is logged in? +",0,676872d623753db5f748a696582d7298a9a28914 +1940999,0,"Missing spaces after `,`. Please use the code sniffer for these types of errors.""",10/25/12 2:11,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/912#discussion_r1940999,2012-10-25T14:11:27Z,2012-10-25T15:15:54Z,markstory,MEMBER,lib/Cake/Model/Validator/CakeValidationRule.php,,263,,,7,"@@ -257,6 +257,9 @@ public function isUpdate($exists = null) { + /** + * Dispatches the validation rule to the given validator method + * ++ * Use ""PluginName.ClassName::method"" as validation rule name to refer to a custom validator object. ++ * /App/Plugin/Model/Validation/ClassName.php ++ * + * @return boolean True if the rule could be dispatched, false otherwise","Missing spaces after `,`. Please use the code sniffer for these types of errors. +",0,b843eda89dc380108a48e5c6fc84036170edc3a2 +1735942,0,"I would name it Logger instead. Or at least I would try to avoid exposing the name trait on it as it is different from interfaces in that they act very much like a class""",10/1/12 18:36,lorenzo,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/885#discussion_r1735942,2012-10-02T06:36:06Z,2012-10-03T03:00:37Z,lorenzo,MEMBER,lib/Cake/Log/LogTrait.php,,22,,,22,"@@ -0,0 +1,41 @@ ++getMock('Cake\Database\Driver\Mysql'); + $dialect = new MysqlSchema($driver); +- $this->assertEquals($expected, $dialect->convertColumn($input)); ++ $method = $this->getPrivateMethod($dialect, '_convertColumn'); ++ $this->assertEquals($expected, $method->invoke($dialect, $input)); + }","Perhaps this method should not directly tested if you need to use reflection hacks to test it. +",0,e88556e91540fd24aba8a434b351897153e56a13 +6698205,0,"Could simple unset them in CommandTask::getShellList from listing. TBH that is hacky at best. Using reflection to check for a attribute marking it as hidden would slow it down considerably but could be a clean way to do it.""",10/1/13 8:22,WyriHaximus,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1644#discussion_r6698205,2013-10-01T20:22:36Z,2013-10-02T20:32:13Z,WyriHaximus,CONTRIBUTOR,lib/Cake/Test/Case/Console/Command/CommandListShellTest.php,,108,,,26,"@@ -98,7 +105,7 @@ public function testMain() { + $expected = ""/\[.*TestPluginTwo.*\] example, welcome/""; + $this->assertRegExp($expected, $output); + +- $expected = ""/\[.*CORE.*\] acl, api, bake, command_list, console, i18n, schema, server, test, testsuite, upgrade/""; ++ $expected = ""/\[.*CORE.*\] acl, api, bake, command_list, completion, console, i18n, schema, server, test, testsuite, upgrade/"";","Could simple unset them in CommandTask::getShellList from listing. TBH that is hacky at best. Using reflection to check for a attribute marking it as hidden would slow it down considerably but could be a clean way to do it. +",0,ac9b7f3882ba5ba8ab240508e46fc8d0ff30b056 +6101145,2,"@jrbasso I tried that, does not work :(""",8/31/13 11:06,lorenzo,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1584#discussion_r6101145,2013-08-31T23:06:08Z,2013-09-01T02:33:40Z,lorenzo,MEMBER,lib/Cake/ORM/Query.php,,,,,1,"@@ -558,6 +558,29 @@ public function mapReduce(callable $mapper = null, callable $reducer = null, $ov + } + + /** ++ * Returns the first result out of executed this query, if the query has not been ++ * executed before, it will set the limit clause to 1 for performance reasons. ++ * ++ * ###Example: ++ * ++ * ``$singleUser = $query->select(['id', 'username'])->first()`` ++ * ++ * @return mixed the first result from the ResultSet ++ */ ++ public function first() { ++ if ($this->_dirty) { ++ $this->limit(1); ++ } ++ $this->bufferResults(); ++ $this->_results = $this->execute(); ++ // Calls foreach so we cursor is rewinded automatically ++ foreach ($this->_results as $row) {","@jrbasso I tried that, does not work :( +",0,88c0ab3a2f5be7840d559e8873b0b6562e915416 +5895963,1,"Well the current code sniffs complain about it. We could always change the rules :smile:""",8/21/13 2:07,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1544#discussion_r5895963,2013-08-21T14:07:47Z,2013-08-24T16:35:52Z,markstory,MEMBER,lib/Cake/Test/TestCase/ORM/QueryTest.php,,,,,1,"@@ -888,4 +903,105 @@ public function testApplyOptions() { + $this->assertEquals($expected, $query->contain()); + } + ++/** ++ * Tests registering mappers with mapReduce() ++ * ++ * @return void ++ */ ++ public function testMapReduceOnlyMapper() { ++ $mapper1 = function() {}; ++ $mapper2 = function() {}; ++ $query = new Query($this->connection, $this->table); ++ $this->assertSame($query, $query->mapReduce($mapper1)); ++ $this->assertSame([['mapper' => $mapper1]], $query->mapReduce()); ++ ++ $this->assertSame($query, $query->mapReduce($mapper1)); ++ $result = $query->mapReduce(); ++ $this->assertEquals([['mapper' => $mapper1], ['mapper' => $mapper2]], $result); ++ } ++ ++/** ++ * Tests registering mappers and reducers with mapReduce() ++ * ++ * @return void ++ */ ++ public function testMapReduceBothMethods() { ++ $mapper1 = function() {}; ++ $mapper2 = function() {}; ++ $reducer1 = function() {}; ++ $reducer2 = function() {}; ++ $query = new Query($this->connection, $this->table); ++ $this->assertSame($query, $query->mapReduce($mapper1, $reducer1)); ++ $this->assertSame( ++ [['mapper' => $mapper1, 'reducer' => $reducer1]], ++ $query->mapReduce() ++ ); ++ ++ $this->assertSame($query, $query->mapReduce($mapper2, $reducer2)); ++ $this->assertSame( ++ [ ++ ['mapper' => $mapper1, 'reducer' => $reducer1], ++ ['mapper' => $mapper2, 'reducer' => $reducer2] ++ ], ++ $query->mapReduce() ++ ); ++ } ++ ++/** ++ * Tests that it is possible to overwrite previous map reducers ++ * ++ * @return void ++ */ ++ public function testOverwriteMapReduce() { ++ $mapper1 = function() {}; ++ $mapper2 = function() {}; ++ $reducer1 = function() {}; ++ $reducer2 = function() {}; ++ $query = new Query($this->connection, $this->table); ++ $this->assertSame($query, $query->mapReduce($mapper1, $reducer1)); ++ $this->assertSame( ++ [['mapper' => $mapper1, 'reducer' => $reducer1]], ++ $query->mapReduce() ++ ); ++ ++ $this->assertSame($query, $query->mapReduce($mapper2, $reducer2, true)); ++ $this->assertSame( ++ [['mapper' => $mapper2, 'reducer' => $reducer2]], ++ $query->mapReduce() ++ ); ++ } ++ ++/** ++ * Tests that multiple map reducers can be stacked ++ * ++ * @return void ++ */ ++ public function testResultsAreWrappedInMapReduce() { ++ $params = [$this->connection, $this->table]; ++ $query = $this->getMock('\Cake\ORM\Query', ['executeStatement'], $params); ++ ++ $statement = $this->getMock('\Database\StatementInterface', ['fetch']); ++ $statement->expects($this->at(0)) ++ ->method('fetch') ++ ->will($this->returnValue(['a' => 1])); ++ $statement->expects($this->at(1)) ++ ->method('fetch') ++ ->will($this->returnValue(['a' => 2])); ++ $statement->expects($this->at(2)) ++ ->method('fetch') ++ ->will($this->returnValue(false)); ++ ++ $query->expects($this->once()) ++ ->method('executeStatement') ++ ->will($this->returnValue($statement)); ++ ++ $query->mapReduce(function($k, $v, $mr) { $mr->emit($v['a']); });","Well the current code sniffs complain about it. We could always change the rules :smile: +",0,65cc26318d4c4fe3e0e590442a746385e46c152a +5575758,0,"A cleaner way could be to json_encode the string casted $message variable.""",8/4/13 22:08,lorenzo,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1477#discussion_r5575758,2013-08-05T10:08:45Z,2013-08-05T11:11:30Z,lorenzo,MEMBER,lib/Cake/View/Helper/FormHelper.php,,,,,1,"@@ -1796,6 +1795,18 @@ public function postLink($title, $url = null, $options = array(), $confirmMessag + } + + /** ++ * Returns a string to be used as onclick handler for confirm messages. ++ * ++ * @param string $message ++ * @param string $action ++ */ ++ protected function getConfirmHandler($message, $action) { ++ $message = str_replace(array(""'"", '""'), array(""\'"", '\""'), $message);","A cleaner way could be to json_encode the string casted $message variable. +",0,560e4dc93b177f2ca5b522c2ca01dcb8d7b53018 +5436927,2,"This is bad, returning early is a good thing.""",7/26/13 17:31,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1455#discussion_r5436927,2013-07-27T05:31:55Z,2013-07-27T05:31:55Z,ADmad,MEMBER,lib/Cake/Controller/Controller.php,,426,,,26,"@@ -422,15 +422,20 @@ public function __set($name, $value) { + case 'here': + case 'webroot': + case 'data': +- return $this->request->{$name} = $value; ++ $this->request->{$name} = $value; ++ break;","This is bad, returning early is a good thing. +",0,340847c19786d301a71ad5a34b9401258d7cc067 +3597681,0,"You could use an interface, I don't have a good grasp of whether an interface is better, or whether the current approach is better. I thought that the if statements that were added wouldn't be required if it were a 'pure' decorator. Something like: ```""",3/31/13 13:30,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1210#discussion_r3597681,2013-04-01T01:30:56Z,2013-04-03T22:16:21Z,markstory,MEMBER,lib/Cake/Model/Datasource/Database/Log/LoggingStatement.php,,,,,1,"@@ -0,0 +1,95 @@ ++isEnumeration($real)) { ++ return count($this->enumerationValues($real));","It is trivial, it can be changed if you consider it appropriate... in fact, I just added this here for consistency I suppose. + +Cause the easiest way to 'hack' into generating enum values was to use PHPMyAdmin's approach: to use the (already available) length logic, which achieves the same cause they have the same shape: `string(255)` as opposed to `enum('a','b')`, but the enum value would end up being a string. + +Because there was a need to understand the enum values and later validate (and handle) them, it was better if they were an array instead, so `enumerationValues()` and `isEnumeration()` were born, and the [test](https://github.com/cakephp/cakephp/pull/1011/files#L1R325) inside `describe()` was done. +",0,8ce174647e132787676a237dd4c84e31895da335 +2098343,1,"Sorry, you are right about that, i think we should always unset it in BaseAuthenticate if present in the userdata, not only if its in the conditions.""",11/12/12 4:25,ceeram,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/949#discussion_r2098343,2012-11-12T15:25:54Z,2012-11-12T15:25:54Z,ceeram,CONTRIBUTOR,lib/Cake/Controller/Component/Auth/DirectAuthenticate.php,,79,,,79,"@@ -0,0 +1,85 @@ ++request->data = array('User' => array('id' => $userId)); ++ * $this->Auth->authenticate = array('Direct' => array('contain' => array('Role.id'), 'fields'=>array('username' => 'id'))); ++ * $result = $this->Auth->login(); ++ * ++ * This has several advantages over using Auth->login($data) directly: ++ * - You keep it dry, especially when using contain ($data would have to have the exact same data). ++ * - No overhead - retrieving the data prior to the login is not necessary. It's short and easy. ++ * - You keep it centralized, only one single mechanism to login (using your Authentication adapters ++ * and its common _findUser() method). It also respects the scope and contain settings specified ++ * in your AppController just as any other adapter. ++ * ++ */ ++class DirectAuthenticate extends BaseAuthenticate { ++ ++/** ++ * Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields` ++ * to find POST data that is used to find a matching record in the `settings.userModel`. Will return false if ++ * there is no post data, username is missing, of if the scope conditions have not been met. ++ * ++ * @param CakeRequest $request The request that contains login information. ++ * @param CakeResponse $response Unused response object. ++ * @return mixed. False on login failure. An array of User data on success. ++ */ ++ public function authenticate(CakeRequest $request, CakeResponse $response) { ++ $userModel = $this->settings['userModel']; ++ list($plugin, $model) = pluginSplit($userModel); ++ ++ $fields = $this->settings['fields']; ++ if (!$this->_checkFields($request, $model, $fields)) { ++ return false; ++ } ++ $conditions = array( ++ $model . '.' . $fields['username'] => $request->data[$model][$fields['username']] ++ ); ++ return $this->_findUser($conditions); ++ } ++ ++/** ++ * Checks the fields to ensure they are supplied. ++ * ++ * @param CakeRequest $request The request that contains login information. ++ * @param string $model The model used for login verification. ++ * @param array $fields The fields to be checked. ++ * @return boolean False if the fields have not been supplied. True if they exist. ++ */ ++ protected function _checkFields(CakeRequest $request, $model, $fields) { ++ if (empty($request->data[$model])) { ++ return false; ++ } ++ if (empty($request->data[$model][$fields['username']])) { ++ return false; ++ } ++ return true; ++ } ++ ++/** ++ * Find a user record using the standard options. ++ * ++ * The $conditions parameter can be a (string)username or an array containing conditions for Model::find('first'). ++ * ++ * @param array $conditions An array of find conditions. ++ * @return Mixed Either false on failure, or an array of user data. ++ */ ++ protected function _findUser($conditions, $password = null) { ++ $userModel = $this->settings['userModel']; ++ list($plugin, $model) = pluginSplit($userModel); ++ $fields = $this->settings['fields']; ++ ++ $user = parent::_findUser($conditions); ++ if (isset($user[$fields['password']])) {","Sorry, you are right about that, i think we should always unset it in BaseAuthenticate if present in the userdata, not only if its in the conditions. +",0,0be9ccd832417a542f3903e0371986a2d6c748de +2015276,2,"I disagree. Passing """"::somestring"""" would be invalid either way and the developers fault (you cant possibly cover all mistakes possible here). But using the type safe check we would at least result in a meaningful exception: """"trigger_error(__d('cake_dev'",11/2/12 0:52,dereuromark,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/913#discussion_r2015276,2012-11-02T11:52:48Z,2013-01-20T08:13:47Z,dereuromark,MEMBER,lib/Cake/Model/Validator/CakeValidationRule.php,,,,,1,"@@ -271,6 +274,17 @@ public function process($field, &$data, &$methods) { + $this->_valid = call_user_func_array($methods[$rule], $this->_ruleParams); + } elseif (class_exists('Validation') && method_exists('Validation', $this->_rule)) { + $this->_valid = call_user_func_array(array('Validation', $this->_rule), $this->_ruleParams); ++ } elseif (strpos($this->_rule, '::')) {","I disagree. Passing ""::somestring"" would be invalid either way and the developers fault (you cant possibly cover all mistakes possible here). +But using the type safe check we would at least result in a meaningful exception: ""trigger_error(__d('cake_dev', 'Could not find custom validation rule %s'"" instead of trying to execute it as a preg match string. +",0,b2cbeeeb501285431bdc7fb2a5b37f260b792261 +6377811,0,"Makes sense, I haven't tested getters/setters yet""",9/16/13 2:30,lorenzo,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1639#discussion_r6377811,2013-09-16T14:30:34Z,2013-10-19T14:50:16Z,lorenzo,MEMBER,Cake/ORM/Entity.php,,,,,1,"@@ -0,0 +1,139 @@ ++get($property); ++ } ++ ++/** ++ * Magic setter to add or edit a property in this entity ++ * ++ * @param string $property the name of the property to set ++ * @param mixed $value the value to set to the property ++ * @return void ++ */ ++ public function __set($property, $value) { ++ $this->set([$property => $value]); ++ } ++ ++/** ++ * Set a hashed array as properties in this entity by converting each ++ * key => value pair into properties in this object. ++ * ++ * ## Example: ++ * ++ * {{ ++ * $entity->set(['name' => 'andrew', 'id' => 1]); ++ * echo $entity->name // prints andrew ++ * echo $entity->id // prints 1 ++ * }} ++ * ++ * @param array $properties list of properties to set ++ * @param boolean $useSetters whether to use setter functions in this object ++ * or bypass them ++ * @return \Cake\ORM\Entity ++ */ ++ public function set(array $properties = [], $useSetters = true) { ++ if (!$useSetters) { ++ $this->_properties = $properties + $this->_properties; ++ return $this; ++ } ++ ++ foreach($properties as $property => $value) { ++ if (method_exists($this, 'set' . ucFirst($property))) { ++ $value = $this->{'set' . ucFirst($property)}($value); ++ } ++ $this->_properties[$property] = $value; ++ } ++ return $this; ++ } ++ ++/** ++ * Returns the value of a property by name ++ * ++ * @param string $property the name of the property to retrieve ++ * @return mixed ++ */ ++ public function &get($property) { ++ $method = 'get' . ucFirst($property); ++ if (method_exists($this, $method)) { ++ $value =& $this->{$method}();","Makes sense, I haven't tested getters/setters yet +",0,299e7b81cf0f0f975497454d75a8e191ce1e3c88 +2827387,0,"This is not something you can just do. It will break every encoded cookie out in the wild.""",1/30/13 4:13,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1100#discussion_r2827387,2013-01-30T15:13:44Z,2013-01-30T18:06:50Z,markstory,MEMBER,lib/Cake/Controller/Component/CookieComponent.php,,,,,1,"@@ -131,11 +131,11 @@ class CookieComponent extends Component { + * Type of encryption to use. + * + * Currently two methods are available: cipher and rijndael +- * Defaults to Security::cipher(); ++ * Defaults to Security::rijndael(); + * + * @var string + */ +- protected $_type = 'cipher'; ++ protected $_type = 'rijndael';","This is not something you can just do. It will break every encoded cookie out in the wild. +",0,c9b14115bf619f0585524e431fae2ac9577a1b98 +5912524,2,"It is too bad a trait cannot implement an interface :(""",8/21/13 11:17,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1544#discussion_r5912524,2013-08-21T23:17:48Z,2013-08-24T16:35:52Z,markstory,MEMBER,lib/Cake/ORM/ResultCollectionTrait.php,,27,,,27,"@@ -0,0 +1,72 @@ ++expects($this->any())->method('message')->will($this->returnValue(array('First Line', 'Second Line', '.Third Line', ''))); + + $data = ""From: CakePHP Test \r\n""; +- $data .= ""Return-Path: CakePHP Return \r\n"";","It seems you are right. I've just checked and indeed it has overwritten my own Return-Path. +",0,796e4b45dd092c7eb1a0ab128280578523191ef3 +3507806,0,"Moving the `!empty($config['log'])` check also inside the `_skipLogging()` function sounds good to me.""",3/24/13 21:23,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1186#discussion_r3507806,2013-03-25T08:23:39Z,2013-03-26T14:10:02Z,ADmad,MEMBER,lib/Cake/Error/ErrorHandler.php,,,,,1,"@@ -110,7 +110,7 @@ class ErrorHandler { + */ + public static function handleException(Exception $exception) { + $config = Configure::read('Exception'); +- if (!empty($config['log'])) { ++ if (!empty($config['log']) && !self::_skipLogging($exception, $config)) {","Moving the `!empty($config['log'])` check also inside the `_skipLogging()` function sounds good to me. +",0,6bf9363217137b6deb1dccb44ecc7d93875d49a3 +1714707,0,"Indentation is not correct here. Also there should be space before and after `=`. You can use the [codesniffer](https://github.com/cakephp/cakephp-codesniffer) to avoid such errors.""",9/27/12 17:27,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/872#discussion_r1714707,2012-09-28T05:27:22Z,2012-09-28T06:07:43Z,ADmad,MEMBER,lib/Cake/Cache/Engine/WincacheEngine.php,,,,,1,"@@ -183,6 +183,7 @@ public function groups() { + * @return boolean success + **/ + public function clearGroup($group) { ++ $success=0;","Indentation is not correct here. Also there should be space before and after `=`. You can use the [codesniffer](https://github.com/cakephp/cakephp-codesniffer) to avoid such errors. +",0,f4565d51fad4ba81906f085cd5abf043d4852365 +1625821,0,"Indeed the fieldList is a whitelist. I too think it should be a protected method.""",9/17/12 17:05,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/851#discussion_r1625821,2012-09-18T05:05:16Z,2012-11-02T09:54:30Z,ADmad,MEMBER,lib/Cake/Model/Model.php,,,,,1,"@@ -2299,6 +2302,29 @@ public function saveAssociated($data = null, $options = array()) { + } + + /** ++ * Helper method for saveAll() and friends, to add foreign key to fieldlist ++ * ++ * @param string $key fieldname to be added to list ++ * @param array $options ++ * @return array $options ++ */ ++ public function addToFieldList($key, $options) {","Indeed the fieldList is a whitelist. I too think it should be a protected method. +",0,7007dba0eb836f852aaca95fada103bc4ba993a9 +1611246,0,"Isn't this a behavior change as well, the count could be > 1 now and pass.""",9/14/12 7:58,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/846#discussion_r1611246,2012-09-14T19:58:35Z,2012-10-01T01:08:06Z,markstory,MEMBER,lib/Cake/View/Helper.php,,530,,,14,"@@ -526,12 +526,11 @@ public function setEntity($entity, $setScope = false) { + + $isHabtm = ( + isset($this->fieldset[$this->_modelScope]['fields'][$parts[0]]['type']) && +- $this->fieldset[$this->_modelScope]['fields'][$parts[0]]['type'] === 'multiple' && +- $count == 1","Isn't this a behavior change as well, the count could be > 1 now and pass. +",0,408e619c9fa6f114ca0531713e1df996165637eb +808124,0,"Missing `{` and `}` as per the [coding standards](http://book.cakephp.org/2.0/en/contributing/cakephp-coding-conventions.html)""",5/11/12 0:00,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/647#discussion_r808124,2012-05-11T12:00:17Z,2012-05-11T12:00:17Z,markstory,MEMBER,lib/Cake/Network/CakeResponse.php,,378,,,4,"@@ -375,6 +375,8 @@ public function send() { + $this->_setContentLength(); + $this->_setContentType(); + foreach ($this->_headers as $header => $value) { ++ if (is_array($value))","Missing `{` and `}` as per the [coding standards](http://book.cakephp.org/2.0/en/contributing/cakephp-coding-conventions.html) +",0,5324365d94c7f598bc133adb0cc64217108efd9a +374831,2,"Sure that makes sense. I also broke the build - AllTests fails because of classnames - so I'm fixing that as well.""",1/22/12 10:01,josegonzalez,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/437#discussion_r374831,2012-01-22T21:01:47Z,2012-01-22T21:01:47Z,josegonzalez,MEMBER,lib/Cake/View/View.php,,308,,,17,"@@ -299,6 +305,9 @@ public function __construct($controller) { + $this->{$var} = $controller->{$var}; + } + $this->_eventManager = $controller->getEventManager(); ++ if (!empty($controller->theme)) {","Sure that makes sense. I also broke the build - AllTests fails because of classnames - so I'm fixing that as well. +",0,c2519e702d26845654e25125412a8ad1485ed73f +284853,1,"Thanks! Fixed. You think after all those code standards commits I would have caught this. :)""",12/10/11 6:07,shama,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/371#discussion_r284853,2011-12-10T17:07:31Z,2011-12-10T17:07:31Z,shama,CONTRIBUTOR,lib/Cake/TestSuite/CakeTestSuite.php,,,,,1,"@@ -52,6 +52,9 @@ public function addTestDirectoryRecursive($directory = '.') { + $files = $Folder->tree(null, false, 'files'); + + foreach ($files as $file) { ++ if (strpos($file, DS.'.') !== false) {","Thanks! Fixed. You think after all those code standards commits I would have caught this. :) +",0,17fcd0534fac8f672ef03b126faebb73f1edcfe1 +112620,2,"I really don't care much if PHP4 people can't run tests. I'd rather be able to ensure code isn't buggy than ensure compatibility with PHP4.""",9/4/11 2:39,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/182#discussion_r112620,2011-09-04T14:39:31Z,2011-09-04T14:39:31Z,markstory,MEMBER,cake/tests/cases/libs/view/helpers/time.test.php,,414,,,6,"@@ -409,6 +409,16 @@ class TimeHelperTest extends CakeTestCase { + */ + function testToRss() { + $this->assertEqual(date('r'), $this->Time->toRss(time())); ++ ++ if (!$this->skipIf(!class_exists('DateTimeZone'), '%s DateTimeZone class not available.')) { ++ $timezones = array('Europe/London', 'Europe/Brussels', 'UTC', 'America/Denver', 'America/Caracas', 'Asia/Kathmandu');","I really don't care much if PHP4 people can't run tests. I'd rather be able to ensure code isn't buggy than ensure compatibility with PHP4. +",0,da4b75c99383957b3974b019a28dd1777765fe6d +6485024,1,"Perhaps reversing the previous decision is best. Having isset() and the ArrayAccess interface work as expected is more important than handling null values. Perhaps a separate method could be used to see if a property is defined?""",9/20/13 0:14,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1639#discussion_r6485024,2013-09-20T12:14:52Z,2013-10-19T14:50:16Z,markstory,MEMBER,Cake/ORM/Entity.php,,,,,1,"@@ -0,0 +1,250 @@ ++ 1, 'name' => 'Andrew'])`` ++ * ++ * @param array $properties hash of properties to set in this entity ++ * @param boolean $useSetters whether use internal setters for properties or not ++ * @return void ++ */ ++ public function __construct(array $properties = [], $useSetters = true) { ++ $this->set($properties, $useSetters); ++ } ++ ++/** ++ * Magic getter to access properties that has be set in this entity ++ * ++ * @param string $property name of the property to access ++ * @return mixed ++ */ ++ public function &__get($property) { ++ return $this->get($property); ++ } ++ ++/** ++ * Magic setter to add or edit a property in this entity ++ * ++ * @param string $property the name of the property to set ++ * @param mixed $value the value to set to the property ++ * @return void ++ */ ++ public function __set($property, $value) { ++ $this->set([$property => $value]); ++ } ++ ++/** ++ * Returns whether this entity contains a property named $property ++ * regardless of if it is empty. ++ * ++ * @see \Cake\ORM\Entity::has() ++ * @param string $property ++ * @return boolean ++ */ ++ public function __isset($property) { ++ return $this->has($property); ++ } ++ ++/** ++ * Removes a property from this entity ++ * ++ * @param string $property ++ * @return void ++ */ ++ public function __unset($property) { ++ $this->unsetProperty($property); ++ } ++ ++/** ++ * Sets a single property inside this entity. ++ * ++ * ### Example: ++ * ++ * ``$entity->set('name', 'Andrew');`` ++ * ++ * It is also possible to mass-assign multiple properties to this entity ++ * with one call by passing a hashed array as properties in the form of ++ * property => value pairs ++ * ++ * ## Example: ++ * ++ * {{ ++ * $entity->set(['name' => 'andrew', 'id' => 1]); ++ * echo $entity->name // prints andrew ++ * echo $entity->id // prints 1 ++ * }} ++ * ++ * Some times it is handy to bypass setter functions in this entity when assigning ++ * properties. You can achieve this by setting the third argument to false when ++ * assigning a single property or the second param when using an array of ++ * properties. ++ * ++ * ### Example: ++ * ++ * ``$entity->set('name', 'Andrew', false);`` ++ * ++ * ``$entity->set(['name' => 'Andrew', 'id' => 1], false);`` ++ * ++ * @param string|array $property the name of property to set or a list of ++ * properties with their respective values ++ * @param mixed|boolean $value the value to set to the property or a boolean ++ * signifying whether to use internal setter functions or not ++ * @param boolean $useSetters whether to use setter functions in this object ++ * or bypass them ++ * @return \Cake\ORM\Entity ++ */ ++ public function set($property, $value = true, $useSetters = true) { ++ if (is_string($property)) { ++ $property = [$property => $value]; ++ } else { ++ $useSetters = $value; ++ } ++ ++ if (!$useSetters) { ++ $this->_properties = $property + $this->_properties; ++ return $this; ++ } ++ ++ foreach ($property as $p => $value) { ++ if (method_exists($this, 'set' . ucFirst($p))) { ++ $value = $this->{'set' . ucFirst($p)}($value); ++ } ++ $this->_properties[$p] = $value; ++ } ++ return $this; ++ } ++ ++/** ++ * Returns the value of a property by name ++ * ++ * @param string $property the name of the property to retrieve ++ * @return mixed ++ */ ++ public function &get($property) { ++ $method = 'get' . ucFirst($property); ++ $value = null; ++ ++ if (isset($this->_properties[$property])) { ++ $value =& $this->_properties[$property]; ++ } ++ ++ if (method_exists($this, $method)) { ++ $value = $this->{$method}($value); ++ } ++ return $value; ++ } ++ ++/** ++ * Returns whether this entity contains a property named $property ++ * regardless of if it is empty. ++ * ++ * ### Example: ++ * ++ * {{{ ++ * $entity = new Entity(['id' => 1, 'name' => null]); ++ * $entity->has('id'); // true ++ * $entity->has('name'); // true ++ * $entity->has('last_name'); // false ++ * }}} ++ * ++ * @param string $property ++ * @return boolean ++ */ ++ public function has($property) { ++ $set = array_key_exists($property, $this->_properties); ++ return $set || method_exists($this, 'get' . ucFirst($property));","Perhaps reversing the previous decision is best. Having isset() and the ArrayAccess interface work as expected is more important than handling null values. Perhaps a separate method could be used to see if a property is defined? +",0,299e7b81cf0f0f975497454d75a8e191ce1e3c88 +6687028,0,"What if you had 2 fields: * 1 string with 1$-dollar signs * 1 string with 1€-euro signs would these 2 not get the same id?""",10/1/13 2:07,kimegede,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1635#discussion_r6687028,2013-10-01T14:07:17Z,2013-12-24T14:20:46Z,kimegede,CONTRIBUTOR,lib/Cake/Test/Case/View/HelperTest.php,,,,,1,"@@ -854,6 +854,32 @@ public function testClean() { + } + + /** ++ * testDomId method ++ * ++ * @return void ++ */ ++ public function testDomId() { ++ $result = $this->Helper->domId('Foo.bar'); ++ $this->assertEquals('FooBar', $result); ++ } ++ ++/** ++ * testDomIdSuffix method ++ * ++ * @return void ++ */ ++ public function testDomIdSuffix() { ++ $result = $this->Helper->domIdSuffix('1 string with 1$-dollar signs', 'xhtml'); ++ $this->assertEquals('1StringWith1-dollarSigns', $result);","What if you had 2 fields: +- 1 string with 1$-dollar signs +- 1 string with 1€-euro signs + +would these 2 not get the same id? +",0,b392254c9211aa521f44f4a4b61bb5b11e4b2b81 +6307484,2,"What IDE do you guys use? Mine has spelling correction so I never run into these mistakes!""",9/11/13 9:21,milesj,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1621#discussion_r6307484,2013-09-11T21:21:57Z,2013-09-12T01:23:58Z,milesj,NONE,lib/Cake/Core/Plugin.php,,,,,1,"@@ -36,37 +34,73 @@ class Plugin { + * + * @var array + */ +- protected static $_plugins = array(); ++ protected static $_plugins = []; + + /** +- * Loads a plugin and optionally loads bootstrapping, routing files or loads a initialization function ++ * Loads a plugin and optionally loads bootstrapping, ++ * routing files or runs a initialization function. ++ * ++ * Plugins only need to be loaded if you want bootstrapping/routes/cli commands to ++ * be exposed. If your plugin doese not expose any of these features you do not need","What IDE do you guys use? Mine has spelling correction so I never run into these mistakes! +",0,0480325e8404f7792144aef7bd1e2b681b24d983 +6189897,0,"@ADmad Very true! testing with ```array_key_exists()``` now. @markstory @ravage84 It does, but I targeted master because I considered a bug: . throwing undefined index when a key is not in the ```viewVars``` array . returning a JSON encoded array whe""",9/5/13 6:36,bar,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1613#discussion_r6189897,2013-09-05T18:36:15Z,2013-09-07T05:39:06Z,bar,CONTRIBUTOR,lib/Cake/View/JsonView.php,,,,,1,"@@ -130,13 +130,15 @@ public function render($view = null, $layout = null) { + */ + protected function _serialize($serialize) { + if (is_array($serialize)) { +- $data = array(); + foreach ($serialize as $alias => $key) { + if (is_numeric($alias)) { + $alias = $key; + } +- $data[$alias] = $this->viewVars[$key]; ++ if (isset($this->viewVars[$key])) {","@ADmad Very true! testing with `array_key_exists()` now. + +@markstory @ravage84 It does, but I targeted master because I considered a bug: +. throwing undefined index when a key is not in the `viewVars` array +. returning a JSON encoded array when no key is found and array is given to `_serialize` +",0,c3ee9a20586eed65edb3fa9b7e6107178bba1b8e +6186448,0,"Won't these changes cause strict errors in applications? Their code might have previously conformed to the old method signatures but will not anymore.""",9/5/13 4:33,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1610#discussion_r6186448,2013-09-05T16:33:49Z,2013-09-05T16:33:49Z,markstory,MEMBER,lib/Cake/Model/ModelBehavior.php,,172,,,22,"@@ -163,9 +165,11 @@ public function afterValidate(Model $model) { + * will abort the save operation. + * + * @param Model $model Model using this behavior ++ * @param array $options Options passed from Model::save(). + * @return mixed False if the operation should abort. Any other result will continue. ++ * @see Model::save() + */ +- public function beforeSave(Model $model) { ++ public function beforeSave(Model $model, $options = array()) {","Won't these changes cause strict errors in applications? Their code might have previously conformed to the old method signatures but will not anymore. +",0,c524645738e666bf4a298d15e6fd6f39d7c6992e +5891580,0,"Should it still be a early-return or something in the lines of: ```php if ($this->_useBufferedResults) { $resultSet = new BufferedResultSet($this, $this->executeStatement()); } else { $resultSet = new ResultSet($this, $this->executeStatemen""",8/20/13 22:08,renansaddam,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1544#discussion_r5891580,2013-08-21T10:08:44Z,2013-08-24T16:35:52Z,renan,CONTRIBUTOR,lib/Cake/ORM/Query.php,,393,,,28,"@@ -375,16 +383,18 @@ public function setResult($results) { + * Resulting object is traversable, so it can be used in any loop as you would + * with an array. + * +- * @return Cake\ORM\ResultSet ++ * @return Cake\ORM\ResultCollectionTrait + */ + public function execute() { + if (isset($this->_results)) { + return $this->_results; + } + if ($this->_useBufferedResults) { +- return new BufferedResultSet($this, parent::execute()); ++ return $this->_applyFormatters(","Should it still be a early-return or something in the lines of: + +``` php +if ($this->_useBufferedResults) { + $resultSet = new BufferedResultSet($this, $this->executeStatement()); +} else { + $resultSet = new ResultSet($this, $this->executeStatement()); +} +return $this->_applyFormatters($resultSet); +``` + +or even: + +``` php +$resultSetClass = ($this->_useBufferedResults) ? 'BufferedResultSet' : 'ResultSet'; +return $this->_applyFormatters(new $resultSetClass($this, $this->executeStatement())); +``` +",0,65cc26318d4c4fe3e0e590442a746385e46c152a +5621790,2,"Because I hadn't seen that, this is very out of place :( Will fix in a few.""",8/6/13 13:23,tigrang,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1483#discussion_r5621790,2013-08-07T01:23:24Z,2013-08-07T01:31:13Z,tigrang,CONTRIBUTOR,lib/Cake/Utility/Debugger.php,,,,,1,"@@ -576,6 +576,11 @@ protected static function _object($var, $depth, $indent) { + $out = ''; + $props = array(); + ++ $type = gettype($var); ++ if ($type === 'unknown type') { ++ return $type; ++ }","Because I hadn't seen that, this is very out of place :( Will fix in a few. +",0,2150e8dce51c485808dafe67b9a415d4e9131ef6 +4604177,0,"Do you mean that some association types don't implement more than one strategy to fetch records?""",6/9/13 2:21,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1340#discussion_r4604177,2013-06-09T14:21:56Z,2013-06-16T04:10:38Z,markstory,MEMBER,lib/Cake/ORM/Association.php,,124,,,124,"@@ -0,0 +1,406 @@ ++{'_' . $property} = $options[$property]; ++ } ++ } ++ ++ $this->_name = $name; ++ $this->_options($options); ++ ++ if (empty($this->_property)) { ++ $this->property($name); ++ } ++ ++ if (!empty($options['strategy'])) { ++ $this->strategy($options['strategy']); ++ } ++ } ++ ++/** ++ * Sets the name for this association. If no argument is passed then the current ++ * configured name will be returned ++ * ++ * @param string $name Name to be assigned ++ * @return string ++ */ ++ public function name($name = null) { ++ if ($name !== null) { ++ $this->_name = $name; ++ } ++ return $this->_name; ++ } ++ ++/** ++ * Sets the table instance for the source side of the association. If no arguments ++ * are passed, the current configured table instance is returned ++ * ++ * @param Cake\ORM\Table $table the instance to be assigned as source side ++ * @return Cake\ORM\Table ++ */ ++ public function source(Table $table = null) { ++ if ($table === null) { ++ return $this->_sourceTable; ++ } ++ return $this->_sourceTable = $table; ++ } ++ ++/** ++ * Sets the table instance for the target side of the association. If no arguments ++ * are passed, the current configured table instance is returned ++ * ++ * @param Cake\ORM\Table $table the instance to be assigned as target side ++ * @return Cake\ORM\Table ++ */ ++ public function target(Table $table = null) { ++ if ($table === null && $this->_targetTable) { ++ return $this->_targetTable; ++ } ++ ++ if ($table !== null) { ++ return $this->_targetTable = $table; ++ } ++ ++ if ($table === null) { ++ $className = $this->_className; ++ $this->_targetTable = Table::build($this->_name, compact('className')); ++ } ++ return $this->_targetTable; ++ } ++ ++/** ++ * Sets a list of conditions to be always included when fetching records from ++ * the target association. If no parameters are passed current list is returned ++ * ++ * @param array $conditions list of conditions to be used ++ * @see Cake\Database\Query::where() for examples on the format of the array ++ * @return array ++ */ ++ public function conditions($conditions = null) { ++ if ($conditions !== null) { ++ $this->_conditions = $conditions; ++ } ++ return $this->_conditions; ++ } ++ ++/** ++ * Sets the name of the field representing the foreign key to the target table. ++ * If no parameters are passed current field is returned ++ * ++ * @param string $key the key to be used to link both tables together ++ * @return string ++ */ ++ public function foreignKey($key = null) { ++ if ($key !== null) { ++ $this->_foreignKey = $key; ++ } ++ return $this->_foreignKey; ++ } ++ ++/** ++ * Sets Whether the records on the target table are dependent on the source table, ++ * often used to indicate that records should be removed is the owning record in ++ * the source table is deleted. ++ * If no parameters are passed current setting is returned. ++ * ++ * @param boolean $dependent ++ * @return boolean ++ */ ++ public function dependent($dependent = null) { ++ if ($dependent !== null) { ++ $this->_dependent = $dependent; ++ } ++ return $this->_dependent; ++ } ++ ++/** ++ * Whether this association can be expressed directly in a query join ++ * ++ * @param array $options custom options key that could alter the return value ++ * @return boolean ++ */ ++ public function canBeJoined($options = []) {","Yes, they are +",0,adb78e6c3992279bb0dcede982f7ba86db765a25 +4520550,0,"You can use the official [codesniffer](https://github.com/cakephp/cakephp-codesniffer).""",6/3/13 23:58,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1323#discussion_r4520550,2013-06-04T11:58:28Z,2013-06-04T14:39:15Z,ADmad,MEMBER,lib/Cake/Model/Model.php,,,,,1,"@@ -1497,6 +1497,14 @@ public function create($data = array(), $filterKey = false) { + } + return $this->data; + } ++ ++/** ++ * This function is a convenient wrapper class to create(false) and, as the name suggests, clears the id, data, and validation errors. ++ * ++ * @return array The current Model::data; after clearing via create(false) ++ * @see Model::create() ++ */ ++ public function clear() { return $this->create(false); }","You can use the official [codesniffer](https://github.com/cakephp/cakephp-codesniffer). +",0,1a164c21422136bbd432574c3a7fc8e7e4ead41a +3788818,2,"I too dislike having huge lists in classes and the memory overhead. Can't we come up with a better way to avoid the extra memory cost for those who don't need this feature by having the list load conditionally from a config file and/or through `Configure:""",4/14/13 18:27,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1229#discussion_r3788818,2013-04-15T06:27:20Z,2013-04-15T06:27:20Z,ADmad,MEMBER,lib/Cake/Network/CakeRequest.php,,992,,,355,"@@ -646,7 +986,13 @@ public function host() { + public function domain($tldLength = 1) { + $segments = explode('.', $this->host()); + $domain = array_slice($segments, -1 * ($tldLength + 1)); +- return implode('.', $domain); ++ $domain = implode('.', $domain); ++ ++ if (in_array('.' . $domain, $this->_slds)) { ++ return $this->domain($tldLength + 1);","I too dislike having huge lists in classes and the memory overhead. Can't we come up with a better way to avoid the extra memory cost for those who don't need this feature by having the list load conditionally from a config file and/or through `Configure::load()/write()`? +",0,db927fd419f56f733eb8106ea0a0f423e2993006 +3503370,0,"All right, I'll fix it up.""",3/23/13 23:07,dereuromark,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1191#discussion_r3503370,2013-03-24T10:07:34Z,2013-03-24T10:09:06Z,dereuromark,MEMBER,lib/Cake/Utility/Validation.php,,624,,,1,"@@ -617,8 +617,8 @@ public static function phone($check, $regex = null, $country = 'all') { + if (is_null($regex)) { + switch ($country) { + case 'us': ++ case 'ca': + case 'all': +- case 'can': + // includes all NANPA members.","All right, I'll fix it up. +",0,f633e59091c41e42741971df7aeb6aa4c21c8d58 +2869489,0,"Should probably also add the solution. i.e. you should either copy or symlink the plugin assets into webroot""",2/2/13 8:24,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1113#discussion_r2869489,2013-02-02T19:24:28Z,2013-02-03T15:37:15Z,ADmad,MEMBER,app/Config/core.php,,97,,,7,"@@ -92,7 +92,9 @@ + * /app/.htaccess + * /app/webroot/.htaccess + * +- * And uncomment the App.baseUrl below: ++ * And uncomment the App.baseUrl below. But keep in mind ++ * that plugin assets such as images, CSS and Javascript files ++ * will not work without url rewriting!","Should probably also add the solution. i.e. you should either copy or symlink the plugin assets into webroot +",0,804753ff6c5c5c5acc73952ae8511f5af0ba2217 +2020462,1,"Better not give the code sniffer reasons to complain :smile: """,11/2/12 8:46,ADmad,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/934#discussion_r2020462,2012-11-02T19:46:04Z,2012-11-03T21:14:08Z,ADmad,MEMBER,lib/Cake/Test/Case/View/XmlViewTest.php,,,,,5,"@@ -64,6 +64,14 @@ public function testRenderWithoutView() { + + $expected = Xml::build(array('response' => array('users' => $data)))->asXML(); + $this->assertSame($expected, $output); ++ ++","Better not give the code sniffer reasons to complain :smile: +",0,c3af467476a9a1b2e46f69e5cef76c3dfa2e205b +2628267,0,"@markstory Why do you trim the dot from the domain? It can cause security issue. The `cakephp.org` cookie domain is accessible only by the `http://cakephp.org`, but the `.cakephp.org` cookie can be accessed by `http://cakephp.org` and `http://bakery.cakep""",1/12/13 13:26,jrbasso,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1057#discussion_r2628267,2013-01-13T00:26:23Z,2013-01-24T02:45:59Z,jrbasso,MEMBER,lib/Cake/Network/Http/Client.php,,,,,1,"@@ -0,0 +1,527 @@ ++get('/users', [], ['type' => 'json']);` ++ * ++ * The `type` option sets both the `Content-Type` and `Accept` header, to ++ * the same mime type. When using `type` you can use either a full mime ++ * type or an alias. If you need different types in the Accept and Content-Type ++ * headers you should set them manually and not use `type` ++ * ++ * ### Using authentication ++ * ++ * By using the `auth` key you can use authentication. The type sub option ++ * can be used to specify which authentication strategy you want to use. ++ * CakePHP comes with a few built-in strategies: ++ * ++ * - Basic ++ * - Digest ++ * - Oauth ++ * ++ * ### Using proxies ++ * ++ * By using the `proxy` key you can set authentication credentials for ++ * a proxy if you need to use one.. The type sub option can be used to ++ * specify which authentication strategy you want to use. ++ * CakePHP comes with built-in support for basic authentication. ++ * ++ */ ++class Client { ++ ++/** ++ * Stored configuration for the client. ++ * ++ * @var array ++ */ ++ protected $_config = [ ++ 'host' => null, ++ 'port' => null, ++ 'scheme' => 'http', ++ 'timeout' => 30, ++ 'ssl_verify_peer' => true, ++ 'ssl_verify_depth' => 5, ++ 'ssl_verify_host' => true, ++ 'redirect' => false, ++ ]; ++ ++/** ++ * List of cookies from responses made with this client. ++ * ++ * Cookies are indexed by the cookie's domain or ++ * request host name. ++ * ++ * @var array ++ */ ++ protected $_cookies = []; ++ ++/** ++ * Adapter for sending requests. Defaults to ++ * Cake\Network\Http\Stream ++ * ++ * @var Cake\Network\Http\Stream ++ */ ++ protected $_adapter; ++ ++/** ++ * Create a new HTTP Client. ++ * ++ * ### Config options ++ * ++ * You can set the following options when creating a client: ++ * ++ * - host - The hostname to do requests on. ++ * - port - The port to use. ++ * - scheme - The default scheme/protocol to use. Defaults to http. ++ * - timeout - The timeout in seconds. Defaults to 30 ++ * - ssl_verify_peer - Whether or not SSL certificates should be validated. ++ * Defaults to true. ++ * - ssl_verify_depth - The maximum certificate chain depth to travers. ++ * Defaults to 5. ++ * - ssl_verify_host - Verify that the certificate and hostname match. ++ * Defaults to true. ++ * - redirect - Number of redirects to follow. Defaults to false. ++ * ++ * @param array $config Config options for scoped clients. ++ */ ++ public function __construct($config = []) { ++ $adapter = 'Cake\Network\Http\Adapter\Stream'; ++ if (isset($config['adapter'])) { ++ $adapter = $config['adapter']; ++ unset($config['adapter']); ++ } ++ $this->config($config); ++ ++ if (is_string($adapter)) { ++ $adapter = new $adapter(); ++ } ++ $this->_adapter = $adapter; ++ } ++ ++/** ++ * Get or set additional config options. ++ * ++ * Setting config will use Hash::merge() for appending into ++ * the existing configuration. ++ * ++ * @param array|null $config Configuration options. null to get. ++ * @return this|array ++ */ ++ public function config($config = null) { ++ if ($config === null) { ++ return $this->_config; ++ } ++ $this->_config = Hash::merge($this->_config, $config); ++ return $this; ++ } ++ ++/** ++ * Get the cookies stored in the Client. ++ * ++ * Returns an array of cookie data arrays. ++ * ++ * @return array ++ */ ++ public function cookies() { ++ return $this->_cookies; ++ } ++ ++/** ++ * Do a GET request. ++ * ++ * The $data argument supports a special `_content` key ++ * for providing a request body in a GET request. This is ++ * generally not used but services like ElasticSearch use ++ * this feature. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The query data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function get($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $body = []; ++ if (isset($data['_content'])) { ++ $body = $data['_content']; ++ unset($data['_content']); ++ } ++ $url = $this->buildUrl($url, $data, $options); ++ return $this->_doRequest( ++ Request::METHOD_GET, ++ $url, ++ $body, ++ $options ++ ); ++ } ++ ++/** ++ * Do a POST request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The post data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function post($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_POST, $url, $data, $options); ++ } ++ ++/** ++ * Do a PUT request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The request data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function put($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_PUT, $url, $data, $options); ++ } ++ ++/** ++ * Do a PATCH request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The request data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function patch($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_PATCH, $url, $data, $options); ++ } ++ ++/** ++ * Do a DELETE request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The request data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function delete($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_DELETE, $url, $data, $options); ++ } ++ ++/** ++ * Helper method for doing non-GET requests. ++ * ++ * @param string $method HTTP method. ++ * @param string $url URL to request. ++ */ ++ protected function _doRequest($method, $url, $data, $options) { ++ $request = $this->_createRequest( ++ $method, ++ $url, ++ $data, ++ $options ++ ); ++ return $this->send($request, $options); ++ } ++ ++/** ++ * Does a recursive merge of the parameter with the scope config. ++ * ++ * @param array $options Options to merge. ++ * @return array Options merged with set config. ++ */ ++ protected function _mergeOptions($options) { ++ return Hash::merge($this->_config, $options); ++ } ++ ++/** ++ * Send a request. ++ * ++ * Used internally by other methods, but can also be used to send ++ * handcrafted Request objects. ++ * ++ * @param Cake\Network\Http\Request $request The request to send. ++ * @param array $options Additional options to use. ++ * @return Cake\Network\Http\Response ++ */ ++ public function send(Request $request, $options = []) { ++ $responses = $this->_adapter->send($request, $options); ++ $host = parse_url($request->url(), PHP_URL_HOST); ++ foreach ($responses as $response) { ++ $this->_storeCookies($response, $host); ++ } ++ return array_pop($responses); ++ } ++ ++/** ++ * Store cookies in a response to be used in future requests. ++ * ++ * Non-expired cookies will be stored for use in future requests ++ * made with the same Client instance. Cookies are not saved ++ * between instances. ++ * ++ * @param Response $response The response to read cookies from ++ * @param string $host The request host, used for getting host names ++ * in case the cookies didn't set a domain. ++ * @return void ++ */ ++ protected function _storeCookies(Response $response, $host) { ++ $cookies = $response->cookies(); ++ foreach ($cookies as $name => $cookie) { ++ $expires = isset($cookie['expires']) ? $cookie['expires'] : false; ++ if ($expires) { ++ $expires = \DateTime::createFromFormat('D, j-M-Y H:i:s e', $expires); ++ } ++ if ($expires && $expires->getTimestamp() <= time()) { ++ continue; ++ } ++ if (empty($cookie['domain'])) { ++ $cookie['domain'] = $host; ++ } ++ $cookie['domain'] = trim($cookie['domain'], '.');","@markstory Why do you trim the dot from the domain? It can cause security issue. The `cakephp.org` cookie domain is accessible only by the `http://cakephp.org`, but the `.cakephp.org` cookie can be accessed by `http://cakephp.org` and `http://bakery.cakephp.org` and all others subdomains. +",0,c0865001dc9b44d763aba9eaa00720fa4e485ddc +2629304,0,"In RFC 2109 an explicitly set domain must always start with a `.` (section 4.2.2). Only if the domain is omitted will the leading `.` be missing (section 4.3.1). Based on the domain matching examples, the rules seem like a cookie's inclusion in a request""",1/13/13 5:26,markstory,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1057#discussion_r2629304,2013-01-13T16:26:02Z,2013-01-24T02:45:59Z,markstory,MEMBER,lib/Cake/Network/Http/Client.php,,,,,1,"@@ -0,0 +1,527 @@ ++get('/users', [], ['type' => 'json']);` ++ * ++ * The `type` option sets both the `Content-Type` and `Accept` header, to ++ * the same mime type. When using `type` you can use either a full mime ++ * type or an alias. If you need different types in the Accept and Content-Type ++ * headers you should set them manually and not use `type` ++ * ++ * ### Using authentication ++ * ++ * By using the `auth` key you can use authentication. The type sub option ++ * can be used to specify which authentication strategy you want to use. ++ * CakePHP comes with a few built-in strategies: ++ * ++ * - Basic ++ * - Digest ++ * - Oauth ++ * ++ * ### Using proxies ++ * ++ * By using the `proxy` key you can set authentication credentials for ++ * a proxy if you need to use one.. The type sub option can be used to ++ * specify which authentication strategy you want to use. ++ * CakePHP comes with built-in support for basic authentication. ++ * ++ */ ++class Client { ++ ++/** ++ * Stored configuration for the client. ++ * ++ * @var array ++ */ ++ protected $_config = [ ++ 'host' => null, ++ 'port' => null, ++ 'scheme' => 'http', ++ 'timeout' => 30, ++ 'ssl_verify_peer' => true, ++ 'ssl_verify_depth' => 5, ++ 'ssl_verify_host' => true, ++ 'redirect' => false, ++ ]; ++ ++/** ++ * List of cookies from responses made with this client. ++ * ++ * Cookies are indexed by the cookie's domain or ++ * request host name. ++ * ++ * @var array ++ */ ++ protected $_cookies = []; ++ ++/** ++ * Adapter for sending requests. Defaults to ++ * Cake\Network\Http\Stream ++ * ++ * @var Cake\Network\Http\Stream ++ */ ++ protected $_adapter; ++ ++/** ++ * Create a new HTTP Client. ++ * ++ * ### Config options ++ * ++ * You can set the following options when creating a client: ++ * ++ * - host - The hostname to do requests on. ++ * - port - The port to use. ++ * - scheme - The default scheme/protocol to use. Defaults to http. ++ * - timeout - The timeout in seconds. Defaults to 30 ++ * - ssl_verify_peer - Whether or not SSL certificates should be validated. ++ * Defaults to true. ++ * - ssl_verify_depth - The maximum certificate chain depth to travers. ++ * Defaults to 5. ++ * - ssl_verify_host - Verify that the certificate and hostname match. ++ * Defaults to true. ++ * - redirect - Number of redirects to follow. Defaults to false. ++ * ++ * @param array $config Config options for scoped clients. ++ */ ++ public function __construct($config = []) { ++ $adapter = 'Cake\Network\Http\Adapter\Stream'; ++ if (isset($config['adapter'])) { ++ $adapter = $config['adapter']; ++ unset($config['adapter']); ++ } ++ $this->config($config); ++ ++ if (is_string($adapter)) { ++ $adapter = new $adapter(); ++ } ++ $this->_adapter = $adapter; ++ } ++ ++/** ++ * Get or set additional config options. ++ * ++ * Setting config will use Hash::merge() for appending into ++ * the existing configuration. ++ * ++ * @param array|null $config Configuration options. null to get. ++ * @return this|array ++ */ ++ public function config($config = null) { ++ if ($config === null) { ++ return $this->_config; ++ } ++ $this->_config = Hash::merge($this->_config, $config); ++ return $this; ++ } ++ ++/** ++ * Get the cookies stored in the Client. ++ * ++ * Returns an array of cookie data arrays. ++ * ++ * @return array ++ */ ++ public function cookies() { ++ return $this->_cookies; ++ } ++ ++/** ++ * Do a GET request. ++ * ++ * The $data argument supports a special `_content` key ++ * for providing a request body in a GET request. This is ++ * generally not used but services like ElasticSearch use ++ * this feature. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The query data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function get($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $body = []; ++ if (isset($data['_content'])) { ++ $body = $data['_content']; ++ unset($data['_content']); ++ } ++ $url = $this->buildUrl($url, $data, $options); ++ return $this->_doRequest( ++ Request::METHOD_GET, ++ $url, ++ $body, ++ $options ++ ); ++ } ++ ++/** ++ * Do a POST request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The post data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function post($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_POST, $url, $data, $options); ++ } ++ ++/** ++ * Do a PUT request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The request data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function put($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_PUT, $url, $data, $options); ++ } ++ ++/** ++ * Do a PATCH request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The request data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function patch($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_PATCH, $url, $data, $options); ++ } ++ ++/** ++ * Do a DELETE request. ++ * ++ * @param string $url The url or path you want to request. ++ * @param array $data The request data you want to send. ++ * @param array $options Additional options for the request. ++ * @return Cake\Network\Http\Response ++ */ ++ public function delete($url, $data = [], $options = []) { ++ $options = $this->_mergeOptions($options); ++ $url = $this->buildUrl($url, [], $options); ++ return $this->_doRequest(Request::METHOD_DELETE, $url, $data, $options); ++ } ++ ++/** ++ * Helper method for doing non-GET requests. ++ * ++ * @param string $method HTTP method. ++ * @param string $url URL to request. ++ */ ++ protected function _doRequest($method, $url, $data, $options) { ++ $request = $this->_createRequest( ++ $method, ++ $url, ++ $data, ++ $options ++ ); ++ return $this->send($request, $options); ++ } ++ ++/** ++ * Does a recursive merge of the parameter with the scope config. ++ * ++ * @param array $options Options to merge. ++ * @return array Options merged with set config. ++ */ ++ protected function _mergeOptions($options) { ++ return Hash::merge($this->_config, $options); ++ } ++ ++/** ++ * Send a request. ++ * ++ * Used internally by other methods, but can also be used to send ++ * handcrafted Request objects. ++ * ++ * @param Cake\Network\Http\Request $request The request to send. ++ * @param array $options Additional options to use. ++ * @return Cake\Network\Http\Response ++ */ ++ public function send(Request $request, $options = []) { ++ $responses = $this->_adapter->send($request, $options); ++ $host = parse_url($request->url(), PHP_URL_HOST); ++ foreach ($responses as $response) { ++ $this->_storeCookies($response, $host); ++ } ++ return array_pop($responses); ++ } ++ ++/** ++ * Store cookies in a response to be used in future requests. ++ * ++ * Non-expired cookies will be stored for use in future requests ++ * made with the same Client instance. Cookies are not saved ++ * between instances. ++ * ++ * @param Response $response The response to read cookies from ++ * @param string $host The request host, used for getting host names ++ * in case the cookies didn't set a domain. ++ * @return void ++ */ ++ protected function _storeCookies(Response $response, $host) { ++ $cookies = $response->cookies(); ++ foreach ($cookies as $name => $cookie) { ++ $expires = isset($cookie['expires']) ? $cookie['expires'] : false; ++ if ($expires) { ++ $expires = \DateTime::createFromFormat('D, j-M-Y H:i:s e', $expires); ++ } ++ if ($expires && $expires->getTimestamp() <= time()) { ++ continue; ++ } ++ if (empty($cookie['domain'])) { ++ $cookie['domain'] = $host; ++ } ++ $cookie['domain'] = trim($cookie['domain'], '.');","In RFC 2109 an explicitly set domain must always start with a `.` (section 4.2.2). Only if the domain is omitted will the leading `.` be missing (section 4.3.1). Based on the domain matching examples, the rules seem like a cookie's inclusion in a request should rely on: +- Secure flag matching. +- Domain matching request host exactly (for default values) +- Domain matching request host at the end of the domain, +- Path matching the request path at the beginning of the path. +- Cookie not being expired. +",0,c0865001dc9b44d763aba9eaa00720fa4e485ddc +5700222,0,"Is this good to go then?""",8/11/13 2:44,dereuromark,cakephp,cakephp,,https://github.com/cakephp/cakephp/pull/1493#discussion_r5700222,2013-08-11T14:44:08Z,2013-08-11T14:44:08Z,dereuromark,MEMBER,lib/Cake/View/Helper/HtmlHelper.php,,921,,,5,"@@ -918,13 +918,10 @@ public function tag($name, $text = null, $options = array()) { + if (empty($name)) { + return $text; + } +- if (is_array($options) && isset($options['escape']) && $options['escape']) { ++ if (isset($options['escape']) && $options['escape']) {","Is this good to go then? +",0,fc2d28974b8080e7670ea1a302e662cbb2fa6489 \ No newline at end of file diff --git a/data/PR inline comments/chosen_sentiment_pr_inline_comments_joined.csv b/data/PR inline comments/chosen_sentiment_pr_inline_comments_joined.csv new file mode 100644 index 0000000..0062117 --- /dev/null +++ b/data/PR inline comments/chosen_sentiment_pr_inline_comments_joined.csv @@ -0,0 +1,272 @@ +comment_id,polarity,text,created_at_gold,author_login,owner,repo,review_id,html_url,created_at_kaiaulu,updated_at,comment_user_login,author_association,file_path,start_line,line,original_start_line,original_line,position,diff_hunk,body,commit_id +6142365,2,"oh, you're absolutely right -- sorry for my confusion! That makes sense, it should add `word.length` to get the next match.""",2013-09-03 12:19:18,eliasdorneles,harvesthq,chosen,,https://github.com/harvesthq/chosen/pull/1037#discussion_r6142365,2013-09-04T00:19:18Z,2013-09-04T00:58:03Z,eliasdorneles,NONE,coffee/lib/abstract-chosen.coffee,,,,,1,"@@ -177,16 +172,22 @@ class AbstractChosen + this.update_results_content this.results_option_build() + this.winnow_results_set_highlight() + +- search_string_match: (search_string, regex) -> +- if regex.test search_string +- return true +- else if @enable_split_word_search and (search_string.indexOf("" "") >= 0 or search_string.indexOf(""["") == 0) +- #TODO: replace this substitution of /\[\]/ with a list of characters to skip. +- parts = search_string.replace(/\[|\]/g, """").split("" "") +- if parts.length +- for part in parts +- if regex.test part +- return true ++ search_string_match: (search_string, words) -> ++ for word in words ++ if search_string.toLowerCase().indexOf(word) < 0 ++ return false ++ return true ++ ++ highlight_search_text: (text, words) -> ++ # sort the query words to highlight the longest first ++ words.sort (a, b) -> b.length - a.length ++ highlight_offset = 10 # 1 + ''.length ++ for word in words ++ startpos = text.toLowerCase().indexOf word ++ while startpos >= 0 ++ text = text.substr(0, startpos) + '' + text.substr(startpos, word.length) + '' + text.substr(startpos + word.length) ++ startpos = text.toLowerCase().indexOf(word, startpos + highlight_offset)","oh, you're absolutely right -- sorry for my confusion! That makes sense, it should add `word.length` to get the next match. +",58146cea40855156adeae1620eeefe306e93933c +5383881,1,"Save here :)""",2013-07-24 08:56:58,koenpunt,harvesthq,chosen,,https://github.com/harvesthq/chosen/pull/1397#discussion_r5383881,2013-07-24T20:56:58Z,2013-07-24T21:52:23Z,koenpunt,CONTRIBUTOR,public/index.proto.html,,,,,1,"@@ -1448,12 +1448,9 @@ + + +