System stringPlayer

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
stringPlayer
Created by Darthfett

Description:
A small collection of functions relating to players. They can be used to convert anything from a player to his hex code colored name, to converting a SubString of players' names to a force containing each player.

Requirements:
+stringFilter

The rest of the documentation can be found in the system code, below:

JASS:
library stringPlayer initializer Init uses stringFilter,stringFind,stringColor
/*
__________________________________________________________________________________

        stringPlayer library, created by Darthfett - version 1.1
        http://www.thehelper.net/forums/showthread.php?t=143590
        
                                Requirements
                                
-vJass compiler (such as JASSHelper, this version compiled for version 0.A.2.7)
                          
+stringFilter library - <a href="http://www.thehelper.net/forums/showthread.php?t=143589" class="link link--internal">http://www.thehelper.net/forums/showthread.php?t=143589</a>

                                Documentation
                                
-NONE of these functions are standalone.  They require the globals block, 
the Init function, and the listed string Libraries

-Credit for this library is not necessary.  Feel free to use it in your map.
If you feel obligated to credit me, I won&#039;t object.  I only ask that you do 
not simply copy and paste the library as your own.

-These functions make use of the vJass hook and will work with systems that
change players&#039; names and playercolors.

                                    API

&lt;CONFIG&gt;

private constant boolean DISPLAY_ERRORS = false
    Set to true/false to enable/disable error messages.
    
&lt;END CONFIG&gt;
                                    
string array playerColorStr
    Contains the hex color code of each player (sorted by PlayerId)
    (Example: &quot;|cffff0303&quot; for Player Red
    
string array playerNames
    Contains the physical names of each player (sorted by PlayerId)
    (Example: &quot;Player 2&quot; for Player 2)

string array playerNamesColored
    Contains the colored physical names of each player (sorted by PlayerId)
    (Example: &quot;|cff0042ffPlayer 2|r&quot; for Player 2)
    (Example: playerColorStr + playerName + CLR_END)

playercolor array playerColor
    Contains the playercolor of each player (sorted by PlayerId)
    (Example: ConvertPlayerColor(0) for Player Red)
    (Example: PLAYER_COLOR_RED for Player Red)
    
string array playerColors
    Contains the color in default order from &quot;red&quot; to &quot;brown&quot;.
    Note that this is not synchronized with each player&#039;s color.
    
force array colorForces
    Contains the forces of all players of each color.
    (Example: colorForces[0] contains all players of the color 
        PLAYER_COLOR_RED/ConvertPlayerColor(0))

function P2HS takes player p returns string
    Player to Hex String returns the hex string (color code) of the player p.
    (Example: &quot;|cffff0303&quot; for Red)
    
function I2HS takes integer i returns string
    Integer to Hex String returns the hex color code of the player indexed by i.
    (Example: &quot;|cffff0303&quot; for Player 0, Red)
    
function P2CN takes player p returns string
    Player to Colored Name returns the name of player p in his respective hex color.
    (Example: &quot;|cffff0303Player 1|r&quot; for Player 0, Red)

function I2CN takes integer i returns string
    Integer to Colored Name returns the name of the player indexed by i in his
    respective player Color.
    (Example: &quot;|cffff0303Player 1|r&quot; for Player 0, Red)
    
function C2PC takes string s returns playercolor
    Color to playercolor converts a color (e.g. &quot;red&quot;) into
    his respective playercolor.
    
function S2P takes string s returns player
    String to Player converts s from a string into a player.
    Works for a player referred to by his color (e.g. &quot;grey&quot;), his number
    (Example: &quot;1&quot; for Player(2)), by his name (e.g. &quot;Player 1&quot; is Player(0)),
    or by a substring of his name.
    (Example: &quot;yer 1&quot; in a game with &quot;Player 1&quot; would refer to him)
    
    This function is NOT case sensitive, and &quot;plAYer&quot; will work the same as 
    &quot;Player&quot;, just as &quot;yeLLOw&quot; will work the same as &quot;yellow&quot;.
    
    Invalid input will result in the output being Player(12) in debug mode,
    or null while not in debug mode.
    
function S2F takes string s returns force
    String to Force converts s from a string into a force.
    Works for players referred to by their color (e.g. &quot;grey&quot;), his number
    (Example: &quot;1&quot; for Player(2)), by their name (e.g. &quot;Player 1&quot; is Player(0)),
    or by a substring of his name
    (Example: &quot;yer 1&quot; in a game with &quot;Player 1&quot; would refer to him)
    
    This function is NOT case sensitive, and &quot;plAYer&quot; will work the same as 
    &quot;Player&quot;, just as &quot;yeLLOw&quot; will work the same as &quot;yellow&quot;.
    
    Invalid input will result in the output being Player(12) in debug mode,
    or null while not in debug mode.
    
function S2PI takes string s returns integer
    String to Player Id converts s from a string into a player number.
    Works for a player referred to by his color (e.g. &quot;grey&quot;), his number 
    (Example: &quot;1&quot; for Player(2)), by his name (e.g. &quot;Player 1&quot; is 0), or by a
    substring of his name
    (Example: &quot;yer 1&quot; in a game with &quot;Player 1&quot; would refer to him)
    
    This function is NOT case sensitive, and &quot;plAYer&quot; will work the same as 
    &quot;Player&quot;, just as &quot;yeLLOw&quot; will work the same as &quot;yellow&quot;.
    
    Invalid input will result in the output being &#039;12&#039;.

private constant integer MAX_NAME_LENGTH = 26
    Do NOT change this.  The max length of any player&#039;s name is 26 characters.
    This is an internal engine limitation, not this system&#039;s limitation.
__________________________________________________________________________________
*/

globals    
    //CONFIG
    private constant boolean DISPLAY_ERRORS = false
    //END CONFIG
    
    string array playerColorStr
    string array playerNames
    string array playerNamesColored
    
    playercolor array playerColor
    force array colorForces
    string array playerColors
    
    
    private constant string C2PC_errorMsg = &quot;ERROR: stringPlayer - function C2PC: Invalid color&quot;
    private constant string S2P_errorMsg = &quot;ERROR: stringPlayer - function S2P: Invalid player string&quot;
    private constant string S2F_errorMsg = &quot;ERROR: stringPlayer - function S2F: Invalid player string&quot;
    private constant string S2PI_errorMsg = &quot;ERROR: stringPlayer - function S2PI: Invalid player string&quot;
    
    private constant integer MAX_NAME_LENGTH = 26
    private hashtable playerTable
    private force tempForce
    private string array tempPlayerColorStr
    private boolean isEmpty
    private player last
endglobals

private function DebugMsg takes string s returns nothing
    if DISPLAY_ERRORS then
        debug call BJDebugMsg(s)
    endif
endfunction

private function CopyForceCallback takes nothing returns nothing
    call ForceAddPlayer(tempForce,GetEnumPlayer())
endfunction

private function CopyForce takes force f returns force
    set tempForce = CreateForce()
    call ForForce(f,function CopyForceCallback)
    return tempForce
endfunction

private function IsForceEmptyCallback takes nothing returns nothing
    set isEmpty = false
endfunction

private function IsForceEmpty takes force f returns boolean
    set isEmpty = true
    call ForForce(f,function IsForceEmptyCallback)
    return isEmpty
endfunction

private function PlayingPlayerInForceCallback takes nothing returns nothing
    if last == null or GetPlayerSlotState(GetEnumPlayer()) == PLAYER_SLOT_STATE_PLAYING then
        set last = GetEnumPlayer()
    endif
endfunction

private function PlayingPlayerInForce takes force f returns player
    set last = null
    call ForForce(f,function PlayingPlayerInForceCallback)
    return last
endfunction
    
private function onColorChange takes player whichPlayer, playercolor color returns nothing
    local integer id = GetHandleId(playerColor[GetPlayerId(whichPlayer)])
    call ForceRemovePlayer(colorForces[id],whichPlayer)
    set id = GetHandleId(color)
    call ForceAddPlayer(colorForces[id],whichPlayer)
    set playerColor[GetPlayerId(whichPlayer)] = color
endfunction

private function onNameChange takes player whichPlayer, string name returns nothing
    local integer i = GetPlayerId(whichPlayer)
    local integer childKey = StringHash(playerNames<i>)
    if name == &quot;&quot; then
        set name = &quot;Player &quot; + I2S(i+1)
    endif
    if StringLength(name) &gt; MAX_NAME_LENGTH then
        set name = SubString(name,0,MAX_NAME_LENGTH)
    endif
    set tempForce = LoadForceHandle(playerTable,0,childKey)
    call ForceRemovePlayer(tempForce,whichPlayer)
    if IsForceEmpty(tempForce) then
        call RemoveSavedHandle(playerTable,0,childKey)
        call DestroyForce(tempForce)
    endif
    
    set childKey = StringHash(name)
    if HaveSavedHandle(playerTable,0,childKey) then
        call ForceAddPlayer(LoadForceHandle(playerTable,0,childKey),whichPlayer)
    else
        set tempForce = CreateForce()
        call ForceAddPlayer(tempForce,whichPlayer)
        call SaveForceHandle(playerTable,0,childKey,tempForce)
    endif
    set playerNames<i> = name
    set playerNamesColored<i> = playerColorStr<i> + playerNames<i> + CLR_END
    set tempForce = null
endfunction

hook SetPlayerColor onColorChange
hook SetPlayerName onNameChange

function P2HS takes player p returns string
    return playerColorStr[GetPlayerId(p)]
endfunction

function I2HS takes integer i returns string
    return playerColorStr<i>
endfunction

function P2CN takes player p returns string
    return playerNamesColored[GetPlayerId(p)]
endfunction

function I2CN takes integer i returns string
    return playerNamesColored<i>
endfunction

function C2PC takes string s returns playercolor
    local integer i = 0
    loop
        exitwhen i &gt;= 12
        if s == playerColors<i> then
            return ConvertPlayerColor(i)
        endif
        set i = i + 1
    endloop
    debug call DebugMsg(C2PC_errorMsg)
    return null
endfunction

function S2P takes string s returns player
    local integer i
    set s = StripMeta(s,true)
    
    set i = StringHash(s)    
    if HaveSavedHandle(playerTable,0,i) then
        return PlayingPlayerInForce(LoadForceHandle(playerTable,0,i))
    endif
    
    if HaveSavedInteger(playerTable,1,i) then
        return PlayingPlayerInForce(colorForces[LoadInteger(playerTable,1,i)])
    endif
    
    set i = S2I(s)
    if I2S(i) == s and i &gt;= 1 and i &lt;= 12 then
        return Player(i-1)
    endif
    
    set i = 0
    loop
        exitwhen i &gt;= 12
        if ContainsString(playerNames<i>,s,false) then
            return Player(i)
        endif
        set i = i + 1
    endloop
    debug call DebugMsg(S2P_errorMsg)
    debug return Player(12)
    return null
endfunction

function S2F takes string s returns force
    local integer i
    set s = StripMeta(s,true)
    
    set i = StringHash(s)    
    if HaveSavedHandle(playerTable,0,i) then
        return CopyForce(LoadForceHandle(playerTable,0,i))
    endif
    
    if HaveSavedInteger(playerTable,1,i) then
        return CopyForce(colorForces[LoadInteger(playerTable,1,i)])
    endif
    
    set tempForce = CreateForce()    
    set i = S2I(s)
    if I2S(i) == s and i &gt;= 1 and i &lt;= 12 then
        call ForceAddPlayer(tempForce,Player(i-1))
        return tempForce
    endif
    
    set i = 0
    loop
        exitwhen i &gt;= 12
        if ContainsString(playerNames<i>,s,false) then
            call ForceAddPlayer(tempForce,Player(i))
        endif
        set i = i + 1
    endloop
    debug if IsForceEmpty(tempForce) then
        debug call DebugMsg(S2F_errorMsg)
    debug endif
    return tempForce
endfunction

function S2PI takes string s returns integer
    local integer i
    set s = StripMeta(s,true)
    
    set i = StringHash(s)    
    if HaveSavedHandle(playerTable,0,i) then
        return GetPlayerId(PlayingPlayerInForce(LoadForceHandle(playerTable,0,i)))
    endif
    
    if HaveSavedHandle(playerTable,1,i) then
        return GetPlayerId(PlayingPlayerInForce(colorForces[LoadInteger(playerTable,1,i)]))
    endif
    
    set i = S2I(s)
    if I2S(i) == s and i &gt;= 1 and i &lt;= 12 then
        return i-1
    endif
    
    set i = 0
    loop
        exitwhen i &gt;= 12
        if ContainsString(playerNames<i>,s,false) then
            return i
        endif
        set i = i + 1
    endloop
    debug call DebugMsg(S2PI_errorMsg)
    return 12
endfunction

private function Init takes nothing returns nothing
    local integer i = 0
    local player p
    local force f

    set playerTable = InitHashtable()
    
    set playerColors[0] = &quot;red&quot;
    set playerColors[1] = &quot;blue&quot;
    set playerColors[2] = &quot;teal&quot;
    set playerColors[3] = &quot;purple&quot;
    set playerColors[4] = &quot;yellow&quot;
    set playerColors[5] = &quot;orange&quot;
    set playerColors[6] = &quot;green&quot;
    set playerColors[7] = &quot;pink&quot;
    set playerColors[8] = &quot;grey&quot;
    set playerColors[9] = &quot;lightblue&quot;
    set playerColors[10] = &quot;darkgreen&quot;
    set playerColors[11] = &quot;brown&quot;
    
    set tempPlayerColorStr[0] = &quot;|cffff0303&quot;
    set tempPlayerColorStr[1] = &quot;|cff0042ff&quot;
    set tempPlayerColorStr[2] = &quot;|cff1ce6b9&quot;
    set tempPlayerColorStr[3] = &quot;|cff540081&quot;
    set tempPlayerColorStr[4] = &quot;|cfffffc01&quot;
    set tempPlayerColorStr[5] = &quot;|cfffeba0e&quot;
    set tempPlayerColorStr[6] = &quot;|cff20c000&quot;
    set tempPlayerColorStr[7] = &quot;|cffr55bb0&quot;
    set tempPlayerColorStr[8] = &quot;|cff959697&quot;
    set tempPlayerColorStr[9] = &quot;|cff7ebff1&quot;
    set tempPlayerColorStr[10] = &quot;|cff107246&quot;
    set tempPlayerColorStr[11] = &quot;|cff4e2a04&quot;
    
    loop
        exitwhen i &gt;= 12
        set colorForces<i> = CreateForce()
        call SaveInteger(playerTable,1,StringHash(playerColors<i>),i)
        set i = i + 1
    endloop
        
    set i = 0
    loop
        exitwhen i &gt;= 12
        set p = Player(i)
        
        set playerColor<i> = GetPlayerColor(p)
        set playerNames<i> = GetPlayerName(p)
        set playerColorStr<i> = tempPlayerColorStr[GetHandleId(playerColor<i>)]
        set playerNamesColored<i> = playerColorStr<i> + playerNames<i> + CLR_END
        
        call ForceAddPlayer(colorForces[GetHandleId(playerColor<i>)],p)
        
        set f = CreateForce()
        call ForceAddPlayer(f,p)
        call SaveForceHandle(playerTable,0,StringHash(playerNames<i>),f)
        set i = i + 1
    endloop
endfunction

endlibrary
/*
__________________________________________________________________________________
*/
library_once stringFind
    function ContainsString takes string s, string find, boolean checkCase returns boolean
        local integer i = 0
        local integer findLen = StringLength(find)
        local integer sLen = StringLength(s)
        if not checkCase then
            set s = StringCase(s,false)
            set find = StringCase(find,false)
        endif
        loop
            exitwhen i+findLen &gt; sLen
            if SubString(s,i,i+findLen) == find then
                return true
            endif
            set i = i + 1
        endloop
        return false
    endfunction
endlibrary

library_once stringColor
    globals
        constant string CLR_END =        &quot;|r&quot;
    endglobals
endlibrary</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>
 

tooltiperror

Super Moderator
Reaction score
231
JASS:
function xred takes string s returns string
return &quot;|cffff0303&quot;+s+&quot;|R&quot;
endfunction
function xblue takes string s returns string
return &quot;|cff0042ff&quot;+s+&quot;|R&quot;
endfunction
function xteal takes string s returns string
return &quot;|cff1ce6b9&quot;+s+&quot;|R&quot;
endfunction
function xpurple takes string s returns string
return &quot;|cff540081&quot;+s+&quot;|R&quot;
endfunction
function xyellow takes string s returns string
return &quot;|cfffffc01&quot;+s+&quot;|R&quot;
endfunction
function xorange takes string s returns string
return &quot;|cfffeba0e&quot;+s+&quot;|R&quot;
endfunction
function xgreen takes string s returns string
return &quot;|cff20c000&quot;+s+&quot;|R&quot;
endfunction
function xpink takes string s returns string
return &quot;|cff55bb0&quot;+s+&quot;|R&quot;
endfunction
function xgray takes string s returns string
return &quot;|cff959697&quot;+s+&quot;|R&quot;
endfunction
function xlb takes string s returns string
return &quot;|cff7ebff1&quot;+s+&quot;|R&quot;
endfunction
function xdg takes string s returns string
return &quot;|cff107246&quot;+s+&quot;|R&quot;
endfunction
function xbrown takes string s returns string
return &quot;|cff4e2a04&quot;+s+&quot;|R&quot;
endfunction

    // &quot;|cffff0303&quot;  //  Red
    // &quot;|cff0042ff&quot;  //  Blue
    // &quot;|cff1ce6b9&quot;  //  Teal
    // &quot;|cff540081&quot;  //  Purple
    // &quot;|cfffffc01&quot;  //  Yellow
    // &quot;|cfffeba0e&quot;  //  Orange
    // &quot;|cff20c000&quot;  //  Green
    // &quot;|cffr55bb0&quot;  //  Pink
    // &quot;|cff959697&quot;  //  gray
    // &quot;|cff7ebff1&quot;  //  lightblue
    // &quot;|cff107246&quot;  //  darkgreen
    // &quot;|cff4e2a04&quot;  //  brown


I have that saved, and I just throw that into my map header.

Then it's just [ljass](xred(s))[/ljass] for player color red. I`ll throw it into an array to.

And it`s vJass-less. -happy face-

Anyway, I think that`s simpler than putting this in your map.

Edit: Forgive my ignorance, I didn`t notice the complexity of your system, thought it was just colors.
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
...

Then it's just [ljass](xred(s))[/ljass] for player color red. I`ll throw it into an array to.

And it`s vJass-less. -happy face-

Anyway, I think that`s simpler than putting this in your map.

Edit: Forgive my ignorance, I didn`t notice the complexity of your system, thought it was just colors.

It's really not just colors. :p This monster sorts players into forces based on their name and color. It has support for name-changing and color-changing systems, and automatically re-organizes the arrays so that they are synced up with it.

Anyways, I updated this library to use the updated string libraries. Thanks to Jesus4Lyf, I can also make this system a little faster (since StringHash is inherently case-insensitive). It skips a few StringCase calls.
 

Blackrage

Ultra Cool Member
Reaction score
25
Correct me if I'm wrong, but shouldn't the order of these two lines be switched around?

JASS:
set playerNamesColored<i> = playerColorStr<i> + playerNames<i> + CLR_END
set playerColorStr<i> = tempPlayerColorStr[GetHandleId(playerColor<i>)]</i></i></i></i></i>


EDIT: Tested. It won't work unless you switch them around.
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
Correct me if I'm wrong, but shouldn't the order of these two lines be switched around?

JASS:
set playerNamesColored<i> = playerColorStr<i> + playerNames<i> + CLR_END
set playerColorStr<i> = tempPlayerColorStr[GetHandleId(playerColor<i>)]</i></i></i></i></i>


EDIT: Tested. It won't work unless you switch them around.


Yea, must have came up when I redid the initializer, thanks. (fixed it) :)
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
Requires a graveyarded resource "stringFilter"
Btw, i know we don't have any official vJass convention but i thought it was pretty common to use LibraryName and not libraryName.
 

Darthfett

Aerospace/Cybersecurity Software Engineer
Reaction score
615
Requires a graveyarded resource "stringFilter"
Btw, i know we don't have any official vJass convention but i thought it was pretty common to use LibraryName and not libraryName.

Don't know why that was graveyarded, I thought I moved mine back after the auto GY. There wasn't any official review, and I've heard good feedback on it.

I wanted the 'string' to be noticeably in common with the other string libraries.
 

Troll-Brain

You can change this now in User CP.
Reaction score
85
I wanted the 'string' to be noticeably in common with the other string libraries.
I don't think it's a valid reason, but it's me, so my opinion doesn't matter if the staff approved it in the current state, anyway it's just a tiny thing ...
But i definitely worry about the library stringType though, as you can see i've spotted things which are wrong.
But it's an other subject and off-topic here.
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +1
  • V-SNES V-SNES:
    Happy Friday!
    +1

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top