//////////////////////////////////////////////////////////////////////
			// Code Example: Using attributes 
			//
			//////////////////////////////////////////////////////////////////////

			// This function is passed the step number. This allows for an application to
			// produce code with several steps as demonstrated.
			// Return 1 if you have finished, 0 if otherwise and -1 to exit.

			int CMyCode::RunMyCode(int step)
			{

			//The code below is sample code. On exiting the function the bodies that
			//exist will be drawn

				
				static PK_BODY_t block, cylinder;
				static PK_ATTDEF_t hatch_attdef=0, colour_attdef=0, name_attdef=0;
				PK_ATTRIB_t hatch_attrib=0, colour_attrib=0, name_attrib=0;
				double hatch_doubles[4] = {1., 1., 0., 0.}, colour_doubles[4] = {0., 1., 0.};
				char name[MAX_NAMELEN];
				PK_CLASS_t name_owners[] = {PK_CLASS_face};
				PK_ATTRIB_field_t name_fields[] = {PK_ATTRIB_field_string_c};
				CString text = _T("");
				int finished = 0;
				static PK_FACE_t *faces = NULL;
				static int n_faces = 0;
				int n_attribs = 0;
				PK_ATTRIB_t* attribs = NULL;
				PK_TOPOL_track_r_t tracking;
				PK_boolean_r_t results;
				PK_BODY_boolean_o_t opts;
				PK_PARTITION_t	partition;
				static PK_PMARK_t pmark;
				int n_new_entities = 0;
				PK_ENTITY_t *new_entities = NULL;
				int n_mod_entities = 0;
				PK_ENTITY_t *mod_entities = NULL;
				int n_del_entities = 0;
				PK_ENTITY_t *del_entities = NULL;
				PK_ATTDEF_t attdefs[1];
				int n_deleted = 0;

				void AskAttribs(int n_attribs, PK_ATTRIB_t *attribs);

				switch( step )
				{
				case 1:
					CExampleAppDoc::ExAppSetStatusBarString("Created a solid block");
					PK_BODY_create_solid_block( 10.0, 10.0, 10.0, NULL, &block );
					break;

				case 2:
					int i;
					PK_EDGE_t *edges;
					int n_edges;

					CExampleAppDoc::ExAppSetStatusBarString("Created a colour attribute on the first face and its edges");
					
					PK_ATTDEF_find("SDL/TYSA_COLOUR", &colour_attdef);
					PK_BODY_ask_faces(block, &n_faces, &faces);
					PK_ATTRIB_create_empty(faces[0], colour_attdef, &colour_attrib);
					PK_ATTRIB_set_doubles(colour_attrib, 0, 3, colour_doubles );
					PK_FACE_ask_edges(faces[0], &n_edges, &edges);
					for(i=0; i< n_edges; i++)
					{
						PK_ATTRIB_create_empty(edges[i], colour_attdef, &colour_attrib);
						PK_ATTRIB_set_doubles(colour_attrib, 0, 3, colour_doubles );
					}
					if(n_edges)
						PK_MEMORY_free(edges);
					break;

				case 3: 
					CExampleAppDoc::ExAppSetStatusBarString("Create a hatch attribute on the second face");
					
					PK_ATTDEF_find("SDL/TYSA_PARAM_HATCH", &hatch_attdef);
					PK_ATTRIB_create_empty(faces[1], hatch_attdef, &hatch_attrib);
					PK_ATTRIB_set_doubles(hatch_attrib, 0, 4, hatch_doubles );
					break;

				case 4: 
					CExampleAppDoc::ExAppSetStatusBarString("Created an attribute definition of class 3 and created an attribute of this type on the third face");
					
					PK_ATTDEF_sf attdef_sf;
					if(name_attdef == 0)
					{	
						strcpy_s(name, MAX_NAMELEN, "example_name");	
						attdef_sf.name = "EXAMPLE_NAME";
						attdef_sf.attdef_class = PK_ATTDEF_class_03_c;
						attdef_sf.n_owner_types = 1;
						attdef_sf.owner_types = name_owners;
						attdef_sf.n_fields = 1;
						attdef_sf.field_types = name_fields;
						PK_ATTDEF_create(&attdef_sf, &name_attdef);
					}
					PK_ATTRIB_create_empty(faces[2], name_attdef, &name_attrib);
					PK_ATTRIB_set_string(name_attrib, 0, name );
					break;

				case 5:
					CExampleAppDoc::ExAppSetStatusBarString("Asked all the attributes on the block");
					
					PK_PART_ask_all_attribs(block, 0, &n_attribs, &attribs);
					AskAttribs(n_attribs, attribs);
					if(n_attribs)
						PK_MEMORY_free(attribs);
					PK_SESSION_ask_curr_partition(&partition);
					// Note that PK_PARTITION_make_pmark is a deprecated function, any new code should use the function that has superseded it.
					PK_PARTITION_make_pmark(partition, &pmark);
					break;

				case 6:
					CExampleAppDoc::ExAppSetStatusBarString("Created a solid cylinder");
				
					PK_BODY_create_solid_cyl( 5.5, 12.0, NULL, &cylinder );
					break;

				case 7:
					CExampleAppDoc::ExAppSetStatusBarString("Subtracted the cylinder from the block");

					PK_BODY_boolean_o_m( opts );
					opts.function = PK_boolean_subtract_c;
					opts.allow_disjoint = PK_LOGICAL_true;
					PK_BODY_boolean_2(block, 1, &cylinder, &opts, &tracking, &results);
					PK_TOPOL_track_r_f( &tracking );
					PK_boolean_r_f( &results );
					break;

				case 8:
					CExampleAppDoc::ExAppSetStatusBarString("Asked all the attributes on the block");
					
					PK_PART_ask_all_attribs(block, 0, &n_attribs, &attribs);
					AskAttribs(n_attribs, attribs);
					if(n_attribs)
						PK_MEMORY_free(attribs);
					break;

				case 9:
					CExampleAppDoc::ExAppSetStatusBarString("Rolled back and created a new solid cylinder");
					
					// Note that PK_PMARK_goto is a deprecated function, any new code should use the function that has superseded it.
					PK_PMARK_goto(pmark, &n_new_entities, &new_entities, &n_mod_entities, &mod_entities, 
						&n_del_entities, &del_entities);
					if(n_new_entities)
						PK_MEMORY_free(new_entities);
					if(n_mod_entities)
						PK_MEMORY_free(mod_entities);
					if(n_del_entities)
						PK_MEMORY_free(del_entities);
					PK_BODY_create_solid_cyl( 5.5, 10.0, NULL, &cylinder );
					break;

				case 10:
					CExampleAppDoc::ExAppSetStatusBarString("United the cylinder and the block");

					PK_BODY_boolean_o_m( opts );
					opts.merge_imprinted = PK_LOGICAL_true;
					PK_BODY_boolean_2(block, 1, &cylinder, &opts, &tracking, &results);
					PK_TOPOL_track_r_f( &tracking );
					PK_boolean_r_f( &results );
					break;

				case 11:
					CExampleAppDoc::ExAppSetStatusBarString("Asked all the attributes on the block");
					
					PK_PART_ask_all_attribs(block, 0, &n_attribs, &attribs);
					AskAttribs(n_attribs, attribs);
					if(n_attribs)
						PK_MEMORY_free(attribs);
					break;

				case 12:
					CExampleAppDoc::ExAppSetStatusBarString("Deleted all the hatch attributes on the block");

					attdefs[0] = hatch_attdef;
					PK_PART_delete_attribs(block,1,attdefs, NULL, &n_deleted );
					PK_PART_ask_all_attribs(block, 0, &n_attribs, &attribs);
					AskAttribs(n_attribs, attribs);
					if(n_attribs)
						PK_MEMORY_free(attribs);
					break;
				case 13:
					CExampleAppDoc::ExAppSetStatusBarString("Deleted all other attributes on the block");
					
					attdefs[0] = PK_ENTITY_null;

					PK_PART_delete_attribs(block, 1, attdefs , NULL, &n_deleted );
					PK_PART_ask_all_attribs(block, 0, &n_attribs, &attribs);
					AskAttribs(n_attribs, attribs);
					if(n_attribs)
						PK_MEMORY_free(attribs);
					break;
				default:
					if(n_faces)
						PK_MEMORY_free(faces);
					finished = 1;
				}

				return finished;
			}

			void AskAttribs(int n_attribs, PK_ATTRIB_t *attribs)
			{
				string message;
				PK_ATTDEF_t attdef;
				PK_ATTDEF_sf_t attdef_sf;
				PK_ENTITY_t ent;

				if(n_attribs == 0)
					message.append("No attributes");
				for(int i=0; i< n_attribs; i++)
				{
					PK_ATTRIB_ask_attdef(attribs[i], &attdef);
					PK_ATTRIB_ask_owner(attribs[i], &ent);

					char pcBuffer[PC_BUFFER_SIZE];

					sprintf_s(pcBuffer, PC_BUFFER_SIZE, "Attribute owner tag %d, attribute tag %d, attdef tag %d\n", ent, attribs[i], attdef);
					message.append(pcBuffer);

					PK_ATTDEF_ask(attdef, &attdef_sf);

					char pcAttdefName[PC_BUFFER_SIZE];
					sprintf_s(pcAttdefName, PC_BUFFER_SIZE, "Name %s\n", attdef_sf.name);
					message.append(pcAttdefName);
					message.append("\n");
				}

				CExampleAppDoc::ExAppShowMessage(message.c_str());
			}