Wolfram Challenges: Behind the Scenes

Rick Hennigan, Wolfram Research

Join the Conversation #WolframTechConf

Agenda

Overview of Wolfram Challenges

The publishing workflow

How it works

Some strategies for managing deployments

Overview

What is Wolfram Challenges?

https://challenges.wolfram.com

Overview

Solving Challenges

Desktop or cloud notebooks

Define your function

Submit

Get feedback

Overview

Progress & Leaderboard

https://challenges.wolfram.com/leaderboard

Challenges you’ve solved are marked

High scores update in real time

Overview

User Profiles

https://challenges.wolfram.com/profile

Initial profile data

Your profile is bound to your $WolframUUID

Users initially have the name “Anonymous”

Initial profile image is generated from a hash of $RequesterWolframUUID

CloudConnect["richardh-testing-1@example.com"];
URLExecute[CloudObject["user:wolframchallenges/public/site/u/img/auto"]]

CloudConnect["richardh@wolfram.com"];
URLExecute[CloudObject["user:wolframchallenges/public/site/u/img/auto"]]

Editing profile

Can change profile information at any time

Export[FileNameJoin@{$HomeDirectory,"Desktop","pizzacat.png"},]

Overview

Authoring New Challenges

Anyone can submit their own Challenge (link at bottom of main page)

NotebookOpen["https://www.wolframcloud.com/objects/wolframchallenges/public/nb/d/AuthoringTemplate.nb"]

Fill in template and submit

It gets reviewed by a content team

Publishing Workflow

Content management dashboard

What happens after you hit submit?

Publishing Workflow

Content management dashboard

Approved Challenges

How it works

Content management dashboard

The dashboard is deployed as a Delayed expression:

CloudConnect["wolframchallenges@wolfram.com"];

CloudGet[CloudObject["user:wolframchallenges/public/site/editing.html"]]

Uses a template to generate an HTTPResponse:

First@%

%["Body"]~StringTake~150

How it works

Content management dashboard

It’s an interface for making calls to the various deployed APIs:

URLExecute[
CloudObject["user:wolframchallenges/public/api/viewdiff"],
{"key1"->"public/commits/6f7d412cfe2908a4/3732298118-6676720","key2"->"public/commits/6f7d412cfe2908a4/3732298295-1133880","target"->"Desktop"},
"NB"
]//NotebookPut

URLExecute[
CloudObject["user:wolframchallenges/public/api/editnotebooks"],
{"hash"->"6f7d412cfe2908a4"},
"NB"
]//NotebookPut

URLExecute[
CloudObject["user:wolframchallenges/public/api/GetChallengeData"],
{"id"->"6f7d412cfe2908a4","property"->"EditHistory"},
"WL"
]//Dataset

How it works

Challenge storage

Challenges are stored as associations of metadata in cloud objects

URLExecute[
CloudObject["user:wolframchallenges/public/api/GetChallengeData"],
{"id"->"ButterfliedStrings","property"->"CloudObject"},
"WL"
]

CloudGet[%]//Dataset

URLExecute[
CloudObject["user:wolframchallenges/public/api/GetChallengeData"],
{"id"->"ButterfliedStrings","property"->"Data"},
"WL"
]//Dataset

How it works

Individual deployments

There are various endpoints deployed as APIFunction, Delayed, FormFunction, etc:

deployed=URLExecute[CloudObject["user:wolframchallenges/public/api/DeployedResourcesMetadata"],{},"WL"];
Dataset@deployed

Counts@Cases[deployed,KeyValuePattern["Location"->co_CloudObject]:>CloudObjectInformation[co,"MIMEType"]]

URLExecute[CloudObject["user:wolframchallenges/public/api/taskstatus"],{},"RawJSON"]["Passing"]//ToExpression//Dataset

Managing Deployments

Challenges

When updating code, how do I know what needs to be redeployed?

How can I find out immediately if one of these deployments isn’t working correctly?

If there’s a mistake in the code somewhere, what can I do to avoid accidentally deleting something important?

Managing Deployments

Tracking code version

Lets look again at the deployed Delayed expression for the content dashboard:

CloudGet[CloudObject["user:wolframchallenges/public/site/editing.html"]]

Notice that it runs CloudGet on a file called EditingSystemWebInterface. This corresponds to the name of the deployment, which we can use to get some properties:

Lookup[deployed,"EditingSystemWebInterface"]//Dataset

Why?

By attaching the package version to the deployed code, you can check if something is potentially out of date:

Lookup[Lookup[Values@deployed,"Metadata"],"$VersionString"]//Counts

Managing Deployments

Storing definitions as WXF

Lets look at the deployed expression for the content management page again:

CloudGet[CloudObject["user:wolframchallenges/public/site/editing.html"]]

str=CloudImport[CloudObject["user:wolframchallenges/public/defs/EditingSystemWebInterface"],"String"];
StringTake[str,UpTo[200]]

All the other deployments work this way as well:

StringTake[CloudImport[CloudObject["user:wolframchallenges/public/defs/GetChallengeDataAPI"],"String"],UpTo[200]]

These byte arrays contain code that initializes all the necessary definitions for the expression to be evaluated.

Why?

Storing definitions in WXF format is more accurate:

f[<||>]:=True;
f[___]:=False;

(* wrong *)
URLExecute@CloudDeploy[Delayed[f[<||>],"WL"]]

(* correct *)
bytes=(Row[, (Spacer1), "BinarySerializeWithDefinitions"])[Unevaluated[f[<||>]]];
URLExecute@CloudDeploy[Delayed[BinaryDeserialize@bytes,"WL"]]

Managing Deployments

Logging errors

Let’s simulate an error:

NotebookPut@ImportByteArray[ByteArray[],"NB"]

logs=URLExecute[CloudObject["user:wolframchallenges/public/api/errorlog"],{},"RawJSON"]["Data"];

log=First@MaximalBy[logs,"Timestamp"]

SystemOpen[log["ViewURL"]]

A full stack trace is saved

Column[Short[#,5]&/@CloudGet[log["Name"]]["Stack"]["Stack"],Dividers->All,Alignment->Left]

Why?

It’s difficult to know if something went wrong in a deployed API, FormFunction, etc since it’s not an interactive session.

Managing Deployments

Runtime error checking

Suppose we wrote our own version of RenameFile:

renameFile[file1_,file2_]:=
(
CopyFile[file1,file2];
DeleteFile[file1];
file2
);

This is not a safe function:

Put[1,"file1"];
Put[2,"file2"];
renameFile["file1","file2"]

The data was lost:

Get/@{"file1","file2"}

This is a bit safer:

saferRenameFile[file1_,file2_]:=
(Row[, (Spacer1), "FailOnMessage"])[
CopyFile[file1,file2];
DeleteFile[file1];
file2
];

Put[1,"file1"];
Put[2,"file2"];
saferRenameFile["file1","file2"]

No data lost:

Get/@{"file1","file2"}

Resource Functions

Many of the utilities discussed have been submitted to the Wolfram Function Repository and are available for anyone to use:

ResourceFunction["BinarySerializeWithDefinitions"]

ResourceFunction["FailOnMessage"]

ResourceFunction["CheckMatch"]

ResourceFunction["SessionInformation"]

(and more are on the way)

Check out the following presentation tomorrow for more information about resource functions and how to use them:

ResourceFunction and Other Repository News

Bob Sandheinrich

1:30 PM - 2:30 PM, Thu, Oct 18, 2018

Questions?