RSS Feed

Author Archives: Arachne Jericho

Writing and Cultural Appropriation

This post is consciously directed at a certain kind of writer. Often they’re dominant Western culture white folks. I know saying this may offend them. All I can say is that I’m trying to explain things from a point of view often ignored by them, something they do not out of maliciousness, but a sort of subconscious puerility.

To get things out of the way: I’m a writer. Not so good with fiction, though I hope to improve; pretty alright with non-fiction, as long as I’m careful and think things through. I’ve read many a writing book and blog, and here are my observations with regards to the writing process in general and how it can lead to trouble with cultural appropriation.

There is this personality trait that many writers express, whether their focus is on fiction or non-fiction, and that is: information sponge. They’re often observant (to a particular degree), and will pick up everything and anything in their brains and most likely it’ll eventually show up in their work, whether consciously or subconsciously drawn from that well of associations.

You can guess the problem with this: often such observation will only scratch the surface, or worse, mistake the aspects of even just the surface. They can miss certain details. Important details. Vital details. Details like, oh, the authenticity of research sources. The nuances of whatever they’re trying to portray. “Little” things like that.

It’s bad enough when they’re screwing up, for instance, the details of a psychological disorder and end up perpetuating stereotypes and shallow facts that ultimately result in more marginalization.

Things get worse when it comes to cultures that are marginalized.

(I’m going to interject an observation here: there’s a particular kind of Western culture that’s dominant due to the history of colonialism and the present of capitalism. Complaining about how people get that stuff wrong, in particular comparing it to the harm wrought about by misunderstandings and stereotyping of marginalized cultures… well, at best it’s like playing a very tiny violin. At worst it’s hypocrisy, especially if you style yourself a seeker of social justice.)

Missing these vital details is… unfortunate, to put it nicely; disrespectful, to put it mildly; and downright rude, to put it bluntly. People say they’re ripping off other cultures, but it’s worse than that: they’re actually riffing off of other cultures, which is by definition a shallow process. Riff’s non-slang meaning, indeed, is a short refrain of another piece of music, and thus pretty shallow compared to the complexity of the original.

On all this, I speak as someone who has, in her own writing, perpetuated this kind of appropriation. It takes one to know one, as they say.

So anyways… what kind of details do writers often miss? What kinds of things do they mess up? From personal and vicarious experience, these are common problems:

  • Taking cultural elements out of context and inserting them into their own culture.

  • Doing the above while leaving members of that culture conspicuously absent.

  • Judging another culture by the values of their own culture.

  • Pressing their own values, mores, traditions onto another culture.

  • Othering members, traditions, society, values, etc. of another culture.

  • Accepting stereotypes as representative of a culture.

  • Treating other cultures as homogenous mono-cultures.

  • Elevating characters of their own culture above those of the other culture.

Basically, if it’s “all about you(r culture)”, you’re engaging in the worst aspects of appropriation.

If you’re interested in avoiding these types of mistakes, well, how to do that? By inverting the above mistakes and making them about the other culture.

  • Respect the original context of cultural elements.

  • Have representatives of that culture around.

  • Don’t press judgement of another culture.

  • Respect the values, mores, society, traditions of the original culture.

  • Treating members of the original culture as people rather than exotics.

  • Rejecting stereotypes (perhaps even inverting them, though that can result in other kinds of fail).

  • Understand the nuances and contours of other cultures.

  • Have true equality amongst characters of all cultures.

Does the above mean that you must include a large variety of other cultures? No; it just means that, for whatever culture(s) you’re currently appropriating, you should do the research and be respectful. For all of these items mean that you must do the research in the right frame of mind.

What can I suggest to further the cause of following the above guidelines? Well, for example:

  • Understand the authenticity of your research sources. Always, always go to the true source: those who are part of that culture you want to write about.

  • Understand that you need to engage in depth, not breadth.

  • Understand that it’s not about your culture; it’s about the other culture.

  • Listen to the accounts of people of that culture. If they say they’re disappointed in such-and-such for this-and-that reason, don’t substitute their experience with your own interpretation.

  • Don’t get fond of yourself as some kind of savior of the culture. In fact, don’t even think this thought.

I think of the these items as rejecting the “tourist” mindset. Just think about what tourists do: the experiences they pursue are not about the culture, but about them experiencing the culture through their own lens. A lot of the mythopoeic fans do this, unfortunately, and I must count myself among those that do (and I hope to avoid this kind of thinking from now on).

As you can perhaps see, this blog post is as much for myself as for others. I’m trying to organize my thoughts on cultural appropriation because, well, I have a strong risk of doing it myself. And frankly, “I have a story to tell” is not an excuse to do it wrong.

So I’m picking up and reading books. It’s costing me a fair amount of money because the true sources are in another country, but as someone who can afford to do that, I’d be a jerk if I didn’t. I’m avoiding the “ooh, so exotic!” mindset of a tourist. I want to understand the culture from an insider’s point of view, not from that of an outsider’s. My characters are all Inuit, for better or worse, and in the futuristic world I’m writing, they have eked things out for themselves. I know the stereotypes of that culture that outsiders have, and knowing is half the battle to avoiding them.

But I must remain conscious of the fact that, no matter how deep I go, I’m only an outsider; what I write is not authentic, and will never be so. It’s folly to pretend otherwise.

Always, it’s a privilege to write about other cultures; it’s not some inalienable right. And privilege is not the best place to speak from.

Movie Marathon Weekend: Harry Potter and the Deathly Hallows

I’ve decided to do this as one big movie.

Things AJ knows before cracking this one open:

  • Book 7.

  • There’s a hug? Involving Voldemort?

Updates in the comments.

Movie Marathon Weekend: Men in Black

Things AJ knows about Men in Black going in:

  • Will Smith is in it.

  • There are aliens, and some kind of Masquerade.

  • There are government agents (the Men in Black).

Updates are in the comments.

Movie Marathon Weekend!

This weekend’s theme is: AJ Has Not Seen Many Movies!

For instance, AJ has not seen Men in Black.

AJ has seen Harry Potter 3, 4, and 6, but not 7.1 or 7.2.

And so tonight, AJ will be doing Live Watches Mark Watches style, which is to make a post and then update the comments to the post rather than the post itself.

The mike will go hot in about 15 minutes.

Bento #2

Bento #2: Lunch

Yesterday’s Lunch was not as successful as I hoped it would be.

  • The (half-of-an) apple/roasted cashew salad resulted in soaked cashews, which I guess is why salad toppings are often kept separate from salads themselves. Or perhaps that’s just how fruit salads are.

  • Chicken-portabello sausage was fine, of course. Aidell’s makes the best pre-cooked chicken sausages.

  • The doggie with the Maurice Sendak feet has raisins for eyes. Those were surprisingly fine.

  • Sugar snap peas were pretty fine. They seem nigh indestructible.

Breakfast was, again, Amazon Flakes, with slivered almonds (ran out of raisins or craisins), and half of an apple.

You’ll note also the picture where my first bento art did not survive the Laptop Lunch’s typical vertical transportation. Admittedly the vertical transportation saved most of the diet 7up from leaking all over, but not all of it. 4 oz of it spilled out. I’m disappointed in the Laptop Lunch bottles. In contrast, the Lock & Lock bottle did not leak in the slightest.

Note: traditional bento boxes typically don’t get vertically transported, but stay horizontal, so the art there is more likely to stay intact.

Bento #2: Breakfast Bento #2: You know what isn't leakproof? Bento art that almost survived transport.

Bento #1

Bento #1: Lunch

(We’re starting over at #1.)

Lunch: Most of an apple (Lady Alice), roasted cashews, sugar snap peas, and portabello-chicken sausage sliced on top of rice.

Breakfast, to enjoy on the ferry: Amazon Flakes (Envirokidz—it’s GF/DF/OF), raisins, slivered almonds; and all of an apple. Sweetened vanilla almond milk added to the bottle in the lower right.

Bento #1: Breakfast Bento #1: Packed

One bag with a jumble of containers is inconvenient, since I’ll want either the breakfast items, or the lunch items, but not both. (Heavens forfend I just want a snack.)

Lunch was mostly self-contained in a Laptop Lunch box, breakfast was not. I have a number of self-contained boxes as well, but cereal with milk is a tough one and tends to only be solved via Lock & Lock containers.

WordPress Theme Tweaks: Liquorice and Responsive Layout

I’m so far loving the Liquorice theme: it’s warm, it has great typography, and it displays full posts in the archives.

But I simply wasn’t satisfied with the width. Here’s the custom CSS recipe I used for widescreen, less widescreen, and small screen.

#canvas {
	width:1150px;
}

#primary-content {
	width:715px;
}

#secondary-content {
	width:300px;
}

@media screen and (max-width: 1240px) {
	#canvas {
		width:96%;
		padding:1%;
	}
	
	#primary-content {
		width:62%;
		margin:1%;
		padding:1%;
	}
	
	#secondary-content {
		width:26%;
		margin:1%;
		padding:1%;
	}
}

@media screen and (max-width: 800px) {
	#canvas {
		width:92%;
		padding:0%;
	}
	
	#primary-content {
		width:92%;
	}
	
	#secondary-content {
		width:92%;
	}
}

WordPress Theme Tweaks: Nuntius

Nuntius is a streamlined, modern, and strangely imperfect theme. If you’ve ever used it, you’ll notice that some of the widgets have weird issues with borders and margins; examples include the Twitter widget, the GoodReads widget, even subscription, archive drop-down, and text widgets.

Here’s my Custom CSS designed to deal specifically with Nuntius’ strangeness in this regard.

.widget_twitter iframe {
	margin:0 20px 10px;
}

.widget_goodreads embed {
	margin:10px 20px 0;
}

.widget_goodreads {
	text-align:center;
}

.widget_goodreads h3 {
	text-align:left;
}

.widget_archive select,.widget_blog_subscription form,div.textwidget {
	margin:10px 20px;
}

“You scare yourself with this story…”

I aggravated my cold by going into work, but I needed to see my bartender, and there were design review meetings, and so on. As it so happens, I will not be getting design reviews done, but I did see my bartender.

This is probably one of the more important sessions in a while, because my bartender had an epiphany.

Subconsciously, and consciously when I out-and-out think about it, I am scared of my parents finding me. That’s what drives the nightmares. This story, of abusive parents following their daughter across the country and locating her and—well, killing her or worse—haunts me.

So he tried to construct the narrative, starting with the past, and talking about how I had built my new life, and I told him to stop because I wanted them separate—the past and the present. I didn’t want them to touch, and I wanted the past to, in fact, disappear. But it’s not so much that they’re intertwined, it’s that I let myself be rooted in the past while ignoring much of the present and how things have changed.

We talked about how I had turned Mother’s Day, which is usually a triggerfest and actually started that way, into awesome. He said that it was a matter of me deciding to make the present matter more than the past that day. He said I should do it more often—yes, the week days are less flexible in terms of being able to run wild and all that, but if I think about it, work is just as much a factor of the present, distinguishing it from the past.

As for the story, my bartender wants me to desensitize myself to it. That means thinking about the story—not just being scared about it, but to think about how the story “works” (or doesn’t work). For instance, my parents would be in their late 60s, which is not exactly spry—even if they were plenty spry when I last saw them. And even if they did find me, there are things I can do so that I feel like I can deal with it if it does occur. (Self-defense classes for abuse survivors, most likely.)

There’s a lot I can do to unravel the story and take away its power over me.

It’s all going to suck.

And yes, lots of this would be circumvented if I happened to find out that my parents (one? both? preferably both) were dead. I don’t like to poke in this bucket, because I’m scared to death of being backtracked. Also, I hate the past. Even though I seem to dwell on it; at the very least, my subconscious dwells on it.

Head First Design Patterns: C# Remote Gumball Machine Proxy

While there is a link to C# code at the official site for Head First Design Patterns, the example for a remote proxy is… complicated, and there is actually no remote Gumball machine implementation.

So here’s my Gumball Machine implementation.

First, the Gumballs library DLL, which will be used by both the client and the server. There’s some slight differences between the structure of my code and that of Head First’s, primarily as I implement base methods with my abstract State class instead of using an interface. Note that the Serializable attribute must be applied to each State subclass as well in order for serialization to work.

using System;
using System.Collections.Generic;
using System.Runtime.Remoting;
using System.Runtime.Serialization;

namespace Gumballs
{
    #region States
    
    /// <summary>
    /// Represents the State of the Gumball Machine.
    /// </summary>
    [Serializable]
    public abstract class State
    {
        [NonSerialized]
        protected GumballMachine _gumballMachine; 
        
        /// <summary>
        /// The Gumball Machine reference; used to change the state of the machine.
        /// </summary>
        protected GumballMachine GumballMachine { 
            get { return _gumballMachine; } 
            private set { _gumballMachine = value; }
        }
        
        /// <summary>
        /// The name of this state.
        /// </summary>
        protected string Name { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="Gumballs.State"/> class.
        /// </summary>
        /// <param name='gumballMachine'>
        /// Gumball machine this state is part of.
        /// </param>
        /// <param name='name'>
        /// Name of this state.
        /// </param>
        protected State (GumballMachine gumballMachine, string name)
        {
            GumballMachine = gumballMachine;
            Name = name;
        }
        
        /// <summary>
        /// The behavior of the state when a quarter is inserted into the machine.
        /// </summary>
        public abstract void InsertQuarter ();
        /// <summary>
        /// The behavior of the state when a quarter is ejected from the machine.
        /// </summary>
        public abstract void EjectQuarter ();
        /// <summary>
        /// The behavior of the state when the machine's crank is turned.
        /// </summary>
        public abstract void TurnCrank ();
        /// <summary>
        /// The behavior of the state when the machine dispenses a gumball (or not).
        /// </summary>
        public abstract void Dispense ();
        
        /// <summary>
        /// Releases the given number of gumballs, and updates the machine's state 
        /// accordingly.
        /// </summary>
        /// <param name='count'>
        /// Number of gumballs to subtract.
        /// </param>
        protected void ReleaseGumballs (int count)
        {            
            for (int i = 1; i <= count; i++) {
                GumballMachine.ReleaseGumball ();
            }
            
            if (GumballMachine.IsEmpty ()) {
                GumballMachine.State = GumballMachine.SoldOutState;
            } else {
                GumballMachine.State = GumballMachine.NoQuarterState;
            }
        }
        
        public override string ToString ()
        {
            return string.Format ("[State {0}]", Name);
        }
    }
    
    /// <summary>
    /// Represents the state of the gumball machine when there is no quarter.
    /// </summary>
    [Serializable]
    public sealed class NoQuarterState : State
    {
        public NoQuarterState (GumballMachine gm) : base(gm, "NoQuarter")
        {
        }
        
        #region implemented abstract members of Gumballs.State
        public override void InsertQuarter ()
        {
            Console.WriteLine ("Accepting quarter");
            GumballMachine.State = GumballMachine.HasQuarterState;
        }

        public override void EjectQuarter ()
        {
            Console.WriteLine ("Cannot eject quarter as there is no quarter");
        }

        public override void TurnCrank ()
        {
            Console.WriteLine ("Can't turn the crank as there is no quarter");
        }

        public override void Dispense ()
        {
            Console.WriteLine ("Can't dispense gumballs because there is no quarter");
        }
        #endregion
    }
    
    /// <summary>
    /// Represents the state of the gumball machine when there is a quarter in the slot.
    /// </summary>
    [Serializable]
    public sealed class HasQuarterState : State
    {
        private Random _randomizer = new Random ();
        
        public HasQuarterState (GumballMachine gm) : base(gm, "HasQuarter")
        {
        }
        
        #region implemented abstract members of Gumballs.State
        public override void InsertQuarter ()
        {
            Console.WriteLine ("Can't insert a second quarter");
        }

        public override void EjectQuarter ()
        {
            Console.WriteLine ("Ejecting quarter");
            GumballMachine.State = GumballMachine.NoQuarterState;
        }

        public override void TurnCrank ()
        {
            Console.WriteLine ("Turning the crank");
            
            if (_randomizer.Next (11) == 10) {
                GumballMachine.State = GumballMachine.WinnerState;
            } else {
                GumballMachine.State = GumballMachine.SoldState;
            }
            GumballMachine.Dispense ();
        }

        public override void Dispense ()
        {
            Console.WriteLine ("Can't dispense; crank must be turned first");
        }
        #endregion
    }
    
    /// <summary>
    /// Represents the state of the gumball machine when there is a successful sale.
    /// </summary>
    [Serializable]
    public sealed class SoldState : State
    {
        public SoldState (GumballMachine gm) : base(gm, "Sold")
        {
        }

        #region implemented abstract members of Gumballs.State
        public override void InsertQuarter ()
        {
            Console.WriteLine ("Please wait, your gumball is arriving");
        }

        public override void EjectQuarter ()
        {
            Console.WriteLine ("Please wait, your gumball is arriving");
        }

        public override void TurnCrank ()
        {
            Console.WriteLine ("Please wait, your gumball is arriving.");
        }

        public override void Dispense ()
        {
            ReleaseGumballs (1);
        }
        #endregion
    }
    
    /// <summary>
    /// Represents the state of the gumball machine when the successful sale is a winner.
    /// </summary>
    [Serializable]
    public sealed class WinnerState : State
    {
        public WinnerState (GumballMachine gm) : base(gm, "Winner")
        {
        }

        #region implemented abstract members of Gumballs.State
        public override void InsertQuarter ()
        {
            Console.WriteLine ("Please wait, your gumballs are arriving");
        }

        public override void EjectQuarter ()
        {
            Console.WriteLine ("Please wait, your gumballs are arriving");
        }

        public override void TurnCrank ()
        {
            Console.WriteLine ("Please wait, your gumballs are arriving");
        }

        public override void Dispense ()
        {
            ReleaseGumballs (2);
        }
        #endregion    
    }
    
    /// <summary>
    /// Represents the state of the gumball machine when there are no more gumballs.
    /// </summary>
    [Serializable]
    public sealed class SoldOutState : State
    {
        public SoldOutState (GumballMachine gm) : base(gm, "SoldOut")
        {
        }
        
        #region implemented abstract members of Gumballs.State
        public override void InsertQuarter ()
        {
            Console.WriteLine ("You cannot insert a quarter, gumballs are sold out");
        }

        public override void EjectQuarter ()
        {
            Console.WriteLine ("You weren't allowed to insert a quarter, gumballs are sold out");
        }

        public override void TurnCrank ()
        {
            Console.WriteLine ("You can't turn the crank, gumballs are sold out");
        }

        public override void Dispense ()
        {
            Console.WriteLine ("Can't dispense, gumballs are sold out");
        }
        #endregion
    }
    
    #endregion
    
    /// <summary>
    /// The Gumball Machine.
    /// </summary>
    public sealed class GumballMachine : MarshalByRefObject, IGumballMachineRemote
    {
        public State NoQuarterState { get; private set; }

        public State HasQuarterState { get; private set; }

        public State SoldState { get; private set; }

        public State WinnerState { get; private set; }

        public State SoldOutState { get; private set; }

        /// <summary>
        /// Gets the current number of gumballs in the machine.
        /// </summary>
        public int Count { get; private set; }

        /// <summary>
        /// Gets or sets the current state of the machine.
        /// </summary>
        public State State { 
            get { return _state; }
            internal set { 
                if (_validStates.Contains (value)) {
                    _state = value;
                } else {
                    throw new ArgumentException ("Invalid state instance " + value);
                }
            }
        }
        
        /// <summary>
        /// Gets the location of the machine.
        /// </summary>
        public string Location { get; private set; }
        
        private State _state;
        private List<State> _validStates;
        
        /// <summary>
        /// Initializes a new instance of the <see cref="Gumballs.GumballMachine"/> class.
        /// </summary>
        /// <param name='location'>
        /// Location of the Gumball machine.
        /// </param>
        /// <param name='count'>
        /// Initial number of gumballs in the machine.
        /// </param>
        public GumballMachine (string location, int count)
        {
            Location = location;
            Count = count;
            
            NoQuarterState = new NoQuarterState (this);
            HasQuarterState = new HasQuarterState (this);
            SoldState = new SoldState (this);
            WinnerState = new WinnerState (this);
            SoldOutState = new SoldOutState (this);
            
            _validStates = new List<State> ();
            _validStates.Add (NoQuarterState);
            _validStates.Add (HasQuarterState);
            _validStates.Add (SoldState);
            _validStates.Add (WinnerState);
            _validStates.Add (SoldOutState);
            
            if (Count > 0) {
                State = NoQuarterState;
            } else {
                State = SoldOutState;
            }
        }
        
        /// <summary>
        /// Inserts a quarter.
        /// </summary>
        public void InsertQuarter ()
        {
            State.InsertQuarter ();
        }
        
        /// <summary>
        /// Ejects the quarter.
        /// </summary>
        public void EjectQuarter ()
        {
            State.EjectQuarter ();
        }
        
        /// <summary>
        /// Turns the crank.
        /// </summary>
        public void TurnCrank ()
        {
            State.TurnCrank ();
        }
        
        /// <summary>
        /// Dispenses gumballs (possibly).
        /// </summary>
        public void Dispense ()
        {
            State.Dispense ();
        }
        
        /// <summary>
        /// Refill the machine with the specified count of gumballs.
        /// </summary>
        /// <param name='count'>
        /// Count of gumballs to refill with.
        /// </param>
        public void Refill (int count)
        {
            Count += count;
            if (State == SoldOutState) {
                State = NoQuarterState;
            }
        }
        
        /// <summary>
        /// Releases a gumball if it's available.
        /// </summary>
        public void ReleaseGumball ()
        {
            if (Count > 0) {
                Console.WriteLine ("Releasing gumball!");
                Count -= 1;            
            } else {
                Console.WriteLine ("No gumballs to release");
            }
                
        }
        
        /// <summary>
        /// Determines whether this instance is empty.
        /// </summary>
        /// <returns>
        /// <c>true</c> if this instance is empty; otherwise, <c>false</c>.
        /// </returns>
        public bool IsEmpty ()
        {
            return Count <= 0;
        }
        
        public override string ToString ()
        {
            return string.Format (
                "[GumballMachine: State={0} Count={1} Location={2}]",
                State,
                Count,
                Location
            );
        }

        #region IGumballMachineRemote implementation
        public int GetCount ()
        {
            return Count;
        }

        public string GetLocation ()
        {
            return Location;
        }

        public State GetState ()
        {
            return State;
        }
        #endregion
    }
    
    /// <summary>
    /// Gumball machine monitor.
    /// </summary>
    public sealed class GumballMachineMonitor
    {
        private IGumballMachineRemote _gumballMachine;
        
        /// <summary>
        /// Initializes a new instance of the <see cref="Gumballs.GumballMachineMonitor"/> class.
        /// </summary>
        /// <param name='gumballMachine'>
        /// Remote gumball machine.
        /// </param>
        public GumballMachineMonitor (IGumballMachineRemote gumballMachine)
        {
            _gumballMachine = gumballMachine;
        }
        
        public void Report ()
        {
            Console.WriteLine ("Gumball machine: {0}", _gumballMachine.GetLocation ());
            Console.WriteLine (
                "Current inventory: {0} gumballs",
                _gumballMachine.GetCount()
            );
            Console.WriteLine ("Current state: {0}", _gumballMachine.GetState ());
        }
    }
    
    #region Remoting
    
    /// <summary>
    /// Remote exception.
    /// </summary>
    public class RemoteException : Exception
    {
        public RemoteException (string message, Exception cause) : base(message, cause) {}

        public RemoteException (string message) : base(message) {}
    }
    
    /// <summary>
    /// Proxy for a remote gumball machine.
    /// </summary>
    public interface IGumballMachineRemote
    {
        /// <summary>
        /// Gets the count of gumballs.
        /// </summary>
        /// <returns>
        /// The count of gumballs.
        /// </returns>
        int GetCount ();

        /// <summary>
        /// Gets the location of the machine.
        /// </summary>
        /// <returns>
        /// The location.
        /// </returns>
        string GetLocation ();

        /// <summary>
        /// Gets the state of the machine.
        /// </summary>
        /// <returns>
        /// The state.
        /// </returns>
        State GetState ();
    }
    
    #endregion
}

Next, the server. Note that we’re using RemotingServices.Marshall to share the actual object created on the heap. This tip I got from Stack Overflow; I didn’t go the extra step with implementing InitializeLifetimeService because this is a really, really short-term project.

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;

namespace Gumballs
{
    class MainClass
    {
        public static void Main (string[] args)
        {
            int count = 0;
            string location = "";
            
            if (args.Length != 2) {
                Console.WriteLine ("Gumballs <location> <inventory>");
                Environment.Exit (1);
            }
            
            location = args [0];
            count = int.Parse (args [1]);
            
            GumballMachine gumballMachine = new GumballMachine (location, count);
            
            Console.WriteLine ("Starting Gumball server...");

            try {
                HttpChannel channel = new HttpChannel (9998);
                ChannelServices.RegisterChannel (channel, false);
                RemotingServices.Marshal (gumballMachine, "GumballMachine");
                                
                Console.WriteLine ("Press Enter to quit\n\n");
                Console.ReadLine ();
            } catch (Exception e) {
                throw new RemoteException (e.Message, e);
            }
        }
    }
}

And now the client, where the monitor runs.

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using Gumballs;

namespace RemoteGumballs
{
    class MainClass
    {
        public static void Main (string[] args)
        {
            try {
                HttpChannel channel = new HttpChannel ();
                ChannelServices.RegisterChannel (channel, false);
            
                IGumballMachineRemote gumballMachineRemote = 
                (IGumballMachineRemote)Activator.GetObject (
                    typeof(IGumballMachineRemote), "http://localhost:9998/GumballMachine");
            
                GumballMachineMonitor monitor = new GumballMachineMonitor (gumballMachineRemote);
                monitor.Report ();
            } catch (Exception e) {
                throw new RemoteException (e.Message, e);
            }
        }
    }
}

I’m using Mono, so it’s all as simple as this:

[Mon May 21, 9:36PM]-(s002)-{~/Projects/CSharp/Gumballs/Gumballs/bin/Debug}
brandywine% mono Gumballs.exe seattle 109
Starting Gumball server...
Press Enter to quit

and this

[Mon May 21, 9:38PM]-(s001)-{..ects/CSharp/Gumballs/RemoteGumballs/bin/Debug}
brandywine% mono RemoteGumballs.exe
Gumball machine: seattle
Current inventory: 109 gumballs
Current state: [State NoQuarter]
Follow

Get every new post delivered to your Inbox.