Friday, March 3, 2017

Why does OSX suck so hard?

I've never had as frustrating an experience working with a computer as I have trying to use Max OS X.  I've used computers since we got a Commodore 64 when I was in elementary school.  I took up DOS quickly, used Linux, Windows.  I've installed DOS token ring drivers to play Warcraft 2 with friends at a LAN party nearly 20 years ago.  I've compiled and installed Linux kernel modules.  Never have I had as much trouble as when trying to use OS X which is supposed to be simple.

Multiple Displays - At my office I have two monitors, I want to disable my laptop screen and just use my two monitors.  In Windows this is simple, and when I plug in the HDMI to show my coworkers something it mirrors one of my displays.  I have no idea how to do either of these things in OSX.  My laptop is off to the side and its screen is primary and unchangeable as far as I can tell.  I can move three screens around, but can't turn off my laptop display.  Easy as pie in Windows 10.  On Mac OSX I'll try to do something and not know what is going on when some stupid window is show on my laptop screen off to the side.  On windows you can make any display primary and mirror any display on another or disable it.  Impossible to do in OSX as far as I can tell, unless you want to mirror all of your displays to show the same thing.

So I want to install something.  On Windows the normal thing is to click on something to download it and click on the downloaded file to install.  On Mac OS X for some reason some things work kinda like that.  Other things I'm supposed to open 'finder' and open 'applications' and drag something into applications from what I downloaded?  It might be in there, it might not.  I might be able to do that or I might just double-click to open in like on windows, but maybe not.  It's impossible to tell.   Why is this so hard?  Why can't I just click on something I downloaded to install it?  It seems like an issue that Windows solved in 1995.

Where do my apps go?  There is a 'launchpad' icon at the bottom of my laptop (not my main screen) window that shows some apps.  How to you get apps to go there?  I don't have a clue.  I think that's when you drag a certain file there from something you download, but sometimes I've drug the wrong thing there and nothing happens when I click it.  When I install something in Windows 10 I can always hit the windows key and find it, then pin it to start and put it exactly where I want so when I hit the windows key I can run it with one click.   Strange that Mac OS X is so far behind.

Working with Safari trying to debug Javascript I can't figure it out.  I have sourcemaps, but they aren'ts howing up.  Looking at resources I thought I would just right-click to open the file or copy the name (it's something like xxxx.hashhashhashhashhashashashash.js) and make sure the .map file was there.  That doesn't work.  The javascript file in resources looks like it should expand and show the sourcemap, but I don't see anything when I click the arrow.  There is no way to tell what is going on.

I use Console on Windows 10 and it is an excellent program to manage my consoles, whether I am running git bash, the windows command shell, or powershell.  OS X's build-in terminal sucks.  I am using something called ITerm right now, but it's not optimal, just one window per console.

After about 6 hours of work I was able to get some things I need installed including nodejs and keypass.   However I'm getting some error building an angular-cli project that I don't know how to fix.

Basically everything I tend to do on Windows is many times more difficult on OSX, if it can be done at all.  And there are few resources to help explain how to do things.  Especially difficult is the way to install new programs, which can vary from program to program.   How does anyone think OS X is easier to use than Windows, and why would anyone use it over Windows, or even Linux?  I mean wow, if you can download something that is supposed to run on Mac and have to open finder and navigate to an application directory, then drag a certain file (god help you if you drag the wrong file or folder) to it, isn't that too fucking complicated?  Then when you do that, it's supposed to appear in the launchpad, but if you dragged the wrong file everything looks like it's fine but it just doesn't do anything?  Come one...

Monday, January 30, 2017

Using SWProxy for summoners war

First you need to install git (or the gui github desktop). Then you can clone the code from https://github.com/kakaroto/SWProxy. Then you can clone the repository in the GUI or from the command line:

git clone https://github.com/kakaroto/SWProxy.git

Now you have to have python 2.7 and pip installed (best to leave default directory of c:\python27). Pip should be installed automatically as of 2.7.9 and higher, but I did it a while ago and had to install it manually.

You need to be able to run python and pip from the command line. You can run "python --version" and "pip --version" to see if they are in your path, otherwise you need to add "C:\python27" and "C:\python27\scripts" to your path.

Next you need to install Microsoft Visual C++ Compiler for Python 2.7. This is required for one of the encryption packages you'll install next with pip because it compiles some C++ code. After installing that you can install the pip packages required with this:

pip install pycrypto dpkt yapsy

To use the proxy your computer has to be attached to the same access point as your phone (unless you setup the routing yourself, but then you don't need to be reading this :)). Check your computer's ip address by running "ipconfig". You should see a wifi adapter with an address like 192.168.1.101:

   IPv4 Address. . . . . . . . . . . : 192.168.1.101
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . : 192.168.1.1


Now you're ready to run the proxy. Go to the folder with the code in it and run "python SWProxy.py". It should start and tell you the ip address and port it is running on:

########################################
# SWParser v0.100 - Summoners War Proxy #
########################################
        Written by:
                KaKaRoTo

        Authors:
                Youness Alaoui
                Leonardo Stern
                Azrethos

        Plugins:
                Generate Visit Friend
                Demo Plugin
                SWARFARM Export Plugin
                Generate Runes
                Print Unit Collection
                Barion Rune Efficiency Plugin

Licensed under LGPLv3 and available at:
        https://github.com/kakaroto/SWProxy

Failed to load GUI dependencies. Switching to CLI mode
Running Proxy server at 192.168.1.101 on port 8080


Now on your phone make sure you're connected to the same wifi access point as your computer and change the settings of the access point to use the proxy 192.168.1.101 (or whatever your ip address is) and port 8080. Then kill your game and restart it or log out and back in. The login packet has all your account data and will produce several files, these are mine:

-rw-r--r-- 1 Jason 197609 2581564 Jan 29 17:35 6202709.json
-rw-r--r-- 1 Jason 197609     714 Jan 29 17:35 6202709-info.csv
-rw-r--r-- 1 Jason 197609   35236 Jan 29 17:35 6202709-monsters.csv
-rw-r--r-- 1 Jason 197609  852821 Jan 29 17:35 6202709-optimizer.json
-rw-r--r-- 1 Jason 197609   91540 Jan 29 17:35 6202709-runes.csv
-rw-r--r-- 1 Jason 197609  696553 Jan 29 17:35 6202709-swarfarm.json


When you visit another player you will get lists for them too but they have much less data:

-rw-r--r-- 1 Jason 197609  942112 Jan 29 17:36 visit-2403436.json
-rw-r--r-- 1 Jason 197609   47097 Jan 29 17:36 visit-2403436-monsters.csv
-rw-r--r-- 1 Jason 197609  931956 Jan 29 17:36 visit-2913465.json
-rw-r--r-- 1 Jason 197609   45451 Jan 29 17:36 visit-2913465-monsters.csv
-rw-r--r-- 1 Jason 197609 1741862 Jan 29 17:35 visit-3563695.json
-rw-r--r-- 1 Jason 197609   88550 Jan 29 17:35 visit-3563695-monsters.csv

Tuesday, September 8, 2015

C# Bouncy Castle File Decryption

I had a hard time finding a good sample of decrypting a PGP-encrypted file in C# so I decided to write this post.

Bouncy Castle works with streams for the most part.  So first you need to open the file as a stream, then get a special decoder stream using PgpUtilities:

// Comment
using (FileStream fsEncryptedFile = File.Open(ENCRYPTED_FILENAME, FileMode.Open)) {
 using (Stream decoderStream = PgpUtilities.GetDecoderStream(fsEncryptedFile))
 {
Next we have to create a PgpObjectFactory using that stream which will provide us with PgpObjects. We're looking for a PgpEncryptedDataList so we might have to skip the first object which could be a marker:
PgpObjectFactory factory = new PgpObjectFactory(decoderStream);
PgpObject obj = factory.NextPgpObject();
if (!(obj is PgpEncryptedDataList))
{
 obj = factory.NextPgpObject(); // first object might be a PGP marker packet
}
PgpEncryptedDataList edl = obj as PgpEncryptedDataList;
With our PgpEncryptedDataList we find PgpPublicKeyEncryptedData, and find the key. Here we open a secret keyring file and find the key based on the KeyId in the data and decrypt it using a passphrase:
PgpEncryptedDataList edl = obj as PgpEncryptedDataList;
foreach (PgpPublicKeyEncryptedData data in edl.GetEncryptedDataObjects())
{
    PgpPrivateKey privateKey = null;
    using (FileStream fsKeyring = File.Open(KEYRING_FILENAME, FileMode.Open))
    {
     PgpSecretKeyRingBundle bundle = new PgpSecretKeyRingBundle(fsKeyring );
     PgpSecretKey secretKey = bundle.GetSecretKey(data.KeyId);
     privateKey = secretKey.ExtractPrivateKey(PASSPHRASE.ToCharArray());
    }
Next we use GetDataStream on our PgpPublicKeyEncryptedData and pass it our private key and create a PgpObjectFactory that will give us our data. If the object is compressed, we uncompress it:
PgpObjectFactory plainFactory = new PgpObjectFactory(data.GetDataStream(privateKey));
PgpObject message = plainFactory.NextPgpObject();
if (message is PgpCompressedData) {
 message = new PgpObjectFactory(((PgpCompressedData)message).GetDataStream()).NextPgpObject();
}
Hopefully that will give us a PgpLiteralData which is what we need to get a stream containing the plain, unencrypted data and write that to a new file:
if (message is PgpLiteralData) {
 PgpLiteralData ld = (PgpLiteralData)message;
 using (FileStream outStream = File.Create(OUTPUT_FILENAME)) {
  Stream inStream = ld.GetInputStream();
  byte [] buffer = new byte[0x100000];
  int count = inStream.Read(buffer, 0, buffer.Length);
  while (count > 0) {
   outStream.Write(buffer, 0, count);
   count = inStream.Read(buffer, 0, buffer.Length);
  }
  outStream.Close();
 }
} else {
 Console.WriteLine("ERROR: Unknown type of message in PGP file: {0}", message.GetType().FullName);
}

Thursday, August 11, 2011

Near Miss Pedantry

"Near miss" is a correct term to describe something that comes close to hitting something else.  I hate it when people say that "near miss" would really be a collision.  The most common meaning of near means close, usually in space.  If I am shooting at a target and I got close to it but didn't quite hit it, that would both be a miss and it would be near the target, therefore it would be a "near miss".  If I had missed way off to the side, it would be a "far miss".  You could say "The miss was near the target", so why can't you call it a "near miss"?

If you have a low ceiling you might say "The ceiling is near".  You could say it was a "near ceiling".  It would be a stretch to interpret this as meaning "It is almost a ceiling, but not quite."

Why do so many pedants skip to the fifth definition when complaining about this term?


Tuesday, July 19, 2011

Intellisense for Google Closure Library in VS 2010 (MVC)

Visual Studio examines your javascript to provide intellisense, and lets you add references to other javascript files to pull info from.  To get closure classes to show up I created a plovr config and did a grep of the whole closure library to find goog.provide calls and converted them to goog.require calls.  Then I did a build to include all the code for closure, resulting in Test.7z (534kb).  It contains the following files:

  • Test\test-config.js: plovr config file, uncomment the module you want to build and run through plovr
  • Test\test.js: goog.require for entire closure library
  • Test\test2.js: missing requires for gears, crypt, test, and some others I'll never use
  • Test\test3.js: also missing goog.ui.editor
  • Test\closure_complete.js: built from test.js, 4.1mb
  • Test\closure_mostly.js: built from test2.js, 2.6mb
  • Test\closure_noeditor.js: built from test3.js, 2.4mb
The easiest way to use them would be to unpack in your Content directory and add this line to the top of your javascript files (has to be the first thing):
/// <reference path="~/Content/Test/closure_mostly.js">

Note: you don't have to add the files to your project, but it uses the same url pathing as if they were part of your web site.

You could also just build your project in WHITESPACE mode and use the generated file.  If you use SIMPLE mode, the closure compiler will shorten your parameter names.  If you use ADVANCED mode the closure compiler would shorten all the names and wouldn't even include code you didn't use.



Monday, July 4, 2011

Building PLOVR on Windows

I wanted to add options to plovr, specifically the ability to output a property map to use for interacting with my server using JSON.

First I installed Mercurial which is needed to get the plovr source code.  I installed it to I:\Programs\Mercurial and added that to my path.

Next I got the plovr source code:
I:\plovr\SRC>hg clone https://plovr.googlecode.com/hg/ plovr

I saw it had a build.xml file so I downloaded apache ant and unzipped it to I:\Programs\apache-ant-1.8.2, adding I:\Programs\apache-ant-1.8.2\bin to my path also.

Building produced an error that bash wasn't found, so I downloaded MSYS (MinGW not needed) and installed it to I:\Programs\msys\1.0.

Then I just started an msys shell and did:
$ cd /i/plovr/src/plovr
$ ant


And voila - /i/plovr/SRC/plovr/build/plovr.jar (i:\plovr\SRC\plovr\build\plovr.jar) is now there!

Friday, June 17, 2011

MiniProfiler with PetaPoco

Integrating PetaPoco with Mvc Mini Profiler can be done by changing a few lines in PetaPoco.cs to wrap the connection with a MvcMiniProfiler.Data.ProfiledDbConnection and by changing a line that gets a command using the factory to use the connection. I've written a simple DbProviderFactory that acts as a proxy to the SQL Server factory so you don't have to make any changes to PetaPoco. You register it by adding a system.data element under the root configuration element in your web.config to register the factory and change your connect strings to use the new provider:

<configuration>
  <system.data>
    <DbProviderFactories>
      <add name="MiniProfiler Data Provider"
           invariant="MiniProfilerSql"
           description="SqlServer wrapper for MiniProfiler"
           type="WebSupport.Code.MiniProfilerSqlProviderFactory, WebSupport"
      />
    </DbProviderFactories>
  </system.data>
  <connectionStrings>
    <add name="Test" providerName="MiniProfilerSql" connectionString="xxxx" />
  </connectionStrings>

Notice in the type attribute that my class is in the WebSupport.Code namespace, the value after the comma shows that it is in the WebSupport assembly I have referenced in my MVC project. If you want to stop using MiniProfiler you can just change your connect strings back to using System.Data.SqlClient as the provider.

Here's the code, you should be able to change it for other providers by changing the provider name in the constructor:

public class MiniProfilerSqlProviderFactory : DbProviderFactory
    {
        public static MiniProfilerSqlProviderFactory Instance = new MiniProfilerSqlProviderFactory();

        DbProviderFactory _factory;

        public override bool CanCreateDataSourceEnumerator
        {
            get
            {
                return _factory.CanCreateDataSourceEnumerator;
            }
        }

        public override DbCommand CreateCommand()
        {
            return _factory.CreateCommand();
        }

        public override DbCommandBuilder CreateCommandBuilder()
        {
            return _factory.CreateCommandBuilder();
        }

        public override DbConnection CreateConnection()
        {
            DbConnection cnn = _factory.CreateConnection();
            return MvcMiniProfiler.Data.ProfiledDbConnection.Get(cnn);
        }

        public override DbConnectionStringBuilder CreateConnectionStringBuilder()
        {
            return _factory.CreateConnectionStringBuilder();
        }

        public override DbDataAdapter CreateDataAdapter()
        {
            return _factory.CreateDataAdapter();
        }

        public override DbDataSourceEnumerator CreateDataSourceEnumerator()
        {
            return _factory.CreateDataSourceEnumerator();
        }

        public override DbParameter CreateParameter()
        {
            return _factory.CreateParameter();
        }

        public override CodeAccessPermission CreatePermission(PermissionState state)
        {
            return _factory.CreatePermission(state);
        }

        public MiniProfilerSqlProviderFactory()
        {
            _factory = DbProviderFactories.GetFactory("System.Data.SqlClient");
        }
    }